Solidity合约中结构体含数组无法完整返回问题排查
问题分析与解决
问题描述
编写了一个Solidity合约存储WRequest类型的结构体数组,结构体包含address类型的receiver、address[]类型的tokenAddresss、uint256[]类型的amounts以及uint类型的approved。调用submitWithdrawRequest添加数据后,通过自动生成的WRequestList getter获取元素时,仅返回receiver和approved,缺失数组字段。
原因分析
Solidity为public数组自动生成的getter函数,对于包含动态数组的结构体,只会返回其中的非动态字段(值类型)。这是因为动态数组属于引用类型,Solidity的ABI规范限制了自动生成getter的返回逻辑,无法直接将动态数组作为返回值的一部分返回。
解决方案
手动编写自定义getter函数,完整返回结构体的所有字段,或者单独编写函数获取每个动态数组字段。推荐前者,更直观易用。
修改后的合约代码
pragma solidity ^0.8.0; contract s { WRequest[] public WRequestList; struct WRequest { address receiver; address[] tokenAddresss; uint256[] amounts; uint approved; } function submitWithdrawRequest(address receiver, address[] memory tokenAddresss, uint256[] memory amounts) public { WRequest memory request = WRequest(receiver, tokenAddresss, amounts, 0); WRequestList.push(request); } // 自定义getter函数,返回完整的WRequest结构体 function getWRequest(uint index) public view returns (WRequest memory) { return WRequestList[index]; } }
修改后的部署脚本
const hre = require("hardhat"); async function main() { const Lock = await hre.ethers.getContractFactory("s"); const lock = await Lock.deploy(); const [owner, account1 ,account2] = await ethers.getSigners(); await lock.deployed(); console.log("deployed") await lock.submitWithdrawRequest(owner.address, [account1.address], [7]) // 调用自定义getter函数获取完整结构体 const list = await lock.getWRequest(0); console.log(list); } main().catch((error) => { console.error(error); process.exitCode = 1; });
测试结果
运行修改后的脚本,输出会包含所有字段:
{ receiver: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', tokenAddresss: [ '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' ], amounts: [ BigNumber { value: "7" } ], approved: BigNumber { value: "0" } }
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

