useDapp与Hardhat调用智能合约返回值不一致问题求助
问题原因与解决方法
我之前也碰到过几乎一模一样的问题,核心差异在于useDapp的useCall钩子返回的value结构和ethers.js直接调用合约函数的返回结构不同:
- 在Hardhat/ethers.js中,当你调用返回数组的合约函数(比如
getArray()返回uint256[]),await contract.getArray()会直接返回这个数组本身,也就是[BigNumber, BigNumber]。 - 但useDapp的
useCall钩子会把合约函数的所有返回值统一包裹在一个外层数组里——哪怕合约只返回一个值(比如这里的单个数组),这个值也会是外层数组的第一个元素。所以此时value的实际结构是[[BigNumber, BigNumber]],而不是你预期的[BigNumber, BigNumber]。
这就解释了你看到的所有异常现象:
JSON.stringify(array)得到[[]]:因为你序列化的是外层数组,内部的BigNumber数组无法直接被JSON序列化,所以显示为空数组array[0]返回undefined:如果你的代码直接返回value,那array就是外层数组,当数据未完全加载时可能出现空数组的情况;加载完成后array[0]才是合约返回的目标数组- 调用
BigNumber.from(array)报错:因为你把整个外层数组传给了BigNumber.from,不符合它的参数要求,自然抛出错误
修复代码
只需要修改你的useGetArray函数,返回value[0]而非value本身,同时完善加载状态的处理:
import { BigNumber } from "ethers"; import { useCall } from "@usedapp/core"; import { Contract } from "@ethersproject/contracts"; export function useGetArray(): BigNumber[] | undefined | Error { const callResult = useCall({ contract: new Contract(myContract, myInterface), method: "getArray", args: [], }); if (!callResult) { // 数据还在加载中,返回undefined return undefined; } const { value, error } = callResult; if (error) { return error; } else { // 取外层数组的第一个元素,也就是合约返回的目标数组 return value[0] as BigNumber[]; }; }
为什么其他调用正常?
你提到另外两个useDapp调用正常,大概率是因为那两个合约函数的返回值是单个值(比如uint256或者address),而非数组类型。此时useCall返回的value是[单个值],不管你是直接返回value[0]还是(不小心)直接返回value在前端使用时都能正常工作;但对于返回数组的函数,value是嵌套数组结构,必须多拆一层才能拿到正确结果。
内容的提问来源于stack exchange,提问作者Zero Cool
相关产品推荐
相关产品推荐

