如何在ethers.js中读取返回tuple类型的Solidity函数数据
问题:ethers.js调用
getLandById返回数据异常 在Remix中调用getLandById能得到预期结果,但用ethers.js调用同一函数时,输出为:
[ '0.007062190', '-0.01878356', '\x00\x00', [Getter] ]
而非预期的:
[ '0.007062190', '-0.01878356', '-0.019048060716011,0.007015231577652,-0.018794627684582,0.007386060761845,-0.018423798497481,0.007132627732498,-0.018677231528875,0.006761798548127,-0.019048060716011,0.007015231577652']
求解决方法及示例。
当前ethers.js代码
let customHttpProvider = new ethers.providers.JsonRpcProvider(API_URL); const contract = new ethers.Contract( Contract_Address, contractAbi, customHttpProvider ); //调用只读方法 async function getLand() { const getLandById = await contract.getLandById("502"); console.log("Land-Info", getLandById); } getLand();
合约ABI片段
{ "inputs": [ { "internalType": "uint256", "name": "landId", "type": "uint256" } ], "name": "getLandById", "outputs": [ { "internalType": "string", "name": "", "type": "string" }, { "internalType": "string", "name": "", "type": "string" }, { "internalType": "string", "name": "", "type": "string" }, { "components": [ { "internalType": "string", "name": "longitude", "type": "string" }, { "internalType": "string", "name": "latitude", "type": "string" } ], "internalType": "struct LandContract.PolygonCoordinates[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function" },
Solidity合约代码片段
function getLandById(uint landId) public view returns ( string memory, string memory, PolygonCoordinates[] memory ) { if (!_exists(landId)) { revert IdNotExist(); } PolygonCoordinates[] memory coordinates = new PolygonCoordinates[]( land[landId].polygonCoordinates.length ); for (uint i = 0; i < land[landId].polygonCoordinates.length; ) { coordinates[i].longitude = land[landId] .polygonCoordinates[i] .longitude; coordinates[i].latitude = land[landId] .polygonCoordinates[i] .latitude; unchecked { i++; } } return (land[landId].longitude, land[landId].latitude, coordinates); }
问题原因与解决方法
1. 核心问题:ABI与合约返回值不匹配
Solidity代码中getLandById明确返回3个值:两个string、一个PolygonCoordinates数组;但ABI的outputs里多定义了一个string类型的返回项。ethers.js完全依赖ABI解析返回数据,定义错误会导致解析混乱,出现\x00\x00这类异常数据。
2. 修复ABI
删除ABI中outputs数组的第三个string类型项,让ABI与合约实际返回值一致:
{ "inputs": [ { "internalType": "uint256", "name": "landId", "type": "uint256" } ], "name": "getLandById", "outputs": [ { "internalType": "string", "name": "", "type": "string" }, { "internalType": "string", "name": "", "type": "string" }, { "components": [ { "internalType": "string", "name": "longitude", "type": "string" }, { "internalType": "string", "name": "latitude", "type": "string" } ], "internalType": "struct LandContract.PolygonCoordinates[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function" },
3. 格式化返回数据
ethers.js返回的是Result对象(兼具数组和属性访问特性),如果需要将坐标数组转为预期的逗号分隔字符串,可手动处理:
let customHttpProvider = new ethers.providers.JsonRpcProvider(API_URL); const contract = new ethers.Contract( Contract_Address, contractAbi, // 使用修复后的ABI customHttpProvider ); //调用只读方法 async function getLand() { const [longitude, latitude, coordinates] = await contract.getLandById("502"); // 将坐标数组转换为预期的逗号分隔格式 const coordStr = coordinates.map(coord => `${coord.longitude},${coord.latitude}`).join(","); console.log("Land-Info", [longitude, latitude, coordStr]); } getLand();
修改后即可得到与Remix一致的预期输出。
内容的提问来源于stack exchange,提问作者Umeraqeel
相关产品推荐
相关产品推荐

