You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不编写getter函数直接读取Solidity合约的状态属性?

解答

无getter读取合约状态属性的实现方案

你示例中的number状态变量未添加public修饰符,默认是internal可见性,Solidity不会为这类变量自动生成外部可调用的getter函数,因此你原来的测试代码中直接调用await this._chars.number会失败。
无需手动编写getter的实现方式是直接读取合约对应存储槽的内容:Solidity的状态变量按声明顺序依次存储在从0开始编号的存储槽中,你示例中的number是第一个状态变量,对应0号存储槽,可通过ethers提供的getStorageAt接口读取,测试代码修改如下:

it('test setting number', async function () {
    // 原代码使用call属于只读模拟调用,不会实际修改链上状态,需改为普通交易调用
    await this._chars.connect(OWNER_ADDRESS).setNumber(123);
    // 读取目标合约0号存储槽的原始数据
    const numberRaw = await ethers.provider.getStorageAt(this._chars.address, 0);
    // 将原始bytes数据转换为数字类型
    const number = ethers.BigNumber.from(numberRaw).toNumber();
    expect(number).to.equal(123);
});

注意:如果要读取的是mapping、动态数组、结构体等复杂类型的状态变量,需要先按照Solidity存储布局规则计算出目标数据对应的存储槽位置后再读取。


层级读取子合约属性的可行性

无法直接通过myInstance.subcontract.property的链式调用读取属性,需要分步骤操作:

  • 如果父合约中的subcontract状态变量是public修饰的,自动生成的getter只会返回子合约的地址,你需要先获取该地址,再用子合约的ABI实例化出子合约对象,再读取子合约的属性。
  • 如果父合约中的subcontract是internal可见性的,你需要先通过读取存储槽的方式获取子合约地址,再实例化子合约对象读取对应属性。

示例代码如下:

// 假设subcontract是父合约的第二个状态变量,对应存储槽编号为1
const subAddrRaw = await ethers.provider.getStorageAt(parentContract.address, 1);
const subContractAddr = ethers.utils.getAddress('0x' + subAddrRaw.slice(-40));
// 实例化子合约对象
const SubContract = await ethers.getContractFactory("你的子合约名称");
const subInstance = SubContract.attach(subContractAddr);
// 读取子合约属性,若属性为internal则继续用读存储槽的方式读取
const targetProp = await subInstance.targetPublicProp();

内容的提问来源于stack exchange,提问作者Gabriel Slomka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 21:24:02