使用JavaScript调用Solidity合约getInfo报错,求排查及交互方案
问题:调用Solidity合约getInfo方法时返回值无效错误
错误信息
Uncaught (in promise) Error: Returned values aren't valid, did it run Out of Gas?
You might also see this error if you are not using the correct ABI for the contract you are
retrieving data from, requesting data from a block number that does not exist,
or querying a node which is not fully synced.
Solidity合约代码
pragma solidity ^0.8.0; contract NFT { uint256 id; string name; string description; address owner; constructor(uint256 _id, string memory _name, string memory _description) public { id = _id; name = _name; description = _description; owner = msg.sender; } function transfer(address newOwner) public { require(msg.sender == owner, "Only the owner can transfer the NFT"); owner = newOwner; } function getInfo() public view returns (uint256, string memory, string memory, address) { return (id, name, description, owner); } function getAddress() external view returns(address) { return address(this); } }
JavaScript连接代码
const connectContract = async () => { const contractAbi = [ { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transfer", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "_id", "type": "uint256" }, { "internalType": "string", "name": "_name", "type": "string" }, { "internalType": "string", "name": "_description", "type": "string" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [], "name": "getAddress", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "getInfo", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" }, { "internalType": "string", "name": "", "type": "string" }, { "internalType": "string", "name": "", "type": "string" }, { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" } ]; // 合约ABI const contractAddress = "[合约地址]"; // 已部署的合约地址 window.web3 = await new Web3(window.ethereum); window.contract = await new window.web3.eth.Contract(contractAbi, contractAddress); document.getElementById("contractArea").innerHTML = "Connected to Contract"; web3.eth.getAccounts(console.log); } const getInfo = async () => { const info = await contract.methods.getInfo().call().then(console.log); } async function main() { const contract = new web3.eth.Contract(contractAbi, contractAddress); // 转移NFT所有权 const newOwner = "[新所有者地址]"; const receipt = await contract.methods.transfer(newOwner).send({ from: web3.eth.defaultAccount }); console.log(receipt); }
用户疑问
当前的合约连接方式是否正确?我遗漏了哪些内容?
解答
合约连接的核心逻辑是正确的,但以下细节问题导致了getInfo调用失败:
1. 只读调用未指定账户
call()虽为只读操作,但部分节点/web3版本需要明确指定from参数才能正确读取合约状态。修改getInfo函数:
const getInfo = async () => { const accounts = await web3.eth.getAccounts(); const info = await contract.methods.getInfo().call({ from: accounts[0] }); console.log(info); }
2. 变量作用域问题
main函数中直接使用的contractAbi和contractAddress是connectContract内部变量,外部无法访问。需将这两个变量提升到全局作用域,或作为参数传递给main。
3. web3.eth.defaultAccount未初始化
该变量不会自动赋值,需手动设置后才能在transfer调用中使用:
async function main() { const accounts = await web3.eth.getAccounts(); web3.eth.defaultAccount = accounts[0]; const contract = new web3.eth.Contract(contractAbi, contractAddress); const newOwner = "[新所有者地址]"; const receipt = await contract.methods.transfer(newOwner).send({ from: web3.eth.defaultAccount }); console.log(receipt); }
4. 确认ABI与合约完全匹配
再次验证:
- 部署的合约代码与你提供的Solidity代码完全一致,未修改返回值结构
- ABI是从部署合约生成的,未手动修改输出参数的顺序或类型
5. 检查节点同步状态
如果使用本地节点(如Ganache),确保节点正常运行且未重置链状态;如果是测试网节点,确认节点已完全同步。
内容的提问来源于stack exchange,提问作者Programmer2B
相关产品推荐
相关产品推荐

