如何使用Web3j库调用ERC721合约的tokenURI()函数?
修复tokenURI调用失败的问题
代码中的核心问题
- 未指定返回值类型:
tokenURI返回字符串,但构造Function时未声明返回值类型,导致Web3j无法正确解码响应。 - 响应值未解码:直接使用
response.value拿到的是ABI编码后的原始数据,需要解码才能得到实际的URI字符串。 - 参数初始化不明确:
Uint256.DEFAULT等价于0,如果你的NFT tokenID不是0,需要传入正确的ID值。 - WebSocket连接容错不足:连接失败后仅打印日志,没有明确的错误状态反馈。
- 同步调用冗余:
sendAsync().get()是阻塞式调用,改用send()更简洁高效。
修正后的代码
private fun getNFTMetadata(tokenId: Long) = viewModelScope.launch(Dispatchers.IO) { val web3j = createWeb3j() ?: run { state.value = "Web3j连接失败" return@launch } // 传入目标NFT的tokenID,替换成你需要查询的具体ID val inputParams = listOf(Uint256(tokenId)) // 声明返回值类型为Solidity string对应的Utf8String val outputParams = listOf(Utf8String()) val function = org.web3j.abi.datatypes.Function( "tokenURI", inputParams, outputParams ) val encodedFunction = FunctionEncoder.encode(function) return try { val response = web3j.ethCall( Transaction.createEthCallTransaction(null, CONTRACT_ADDRESS, encodedFunction), DefaultBlockParameterName.LATEST ).send() if (!response.isStatusOK) { state.value = "调用失败: ${response.error.message}" return@launch } // 解码ABI编码的响应结果 val decodedResults = FunctionDecoder.decodeFunctionResult(function, response.value) val tokenUri = decodedResults.first().value as String state.value = tokenUri // 拿到URI后可继续请求元数据(示例:HTTP GET获取JSON) // fetchNFTMetadata(tokenUri) } catch (e: Exception) { state.value = "调用异常: ${e.message}" e.printStackTrace() } } private fun createWeb3j(): Web3j? { return try { val webSocketService = WebSocketService(WEB_SOCKET_URL, true) webSocketService.connect() Web3j.build(webSocketService) } catch (e: ConnectException) { e.printStackTrace() null } }
关键修改说明
- 声明返回值类型:构造
Function时传入listOf(Utf8String()),让Web3j明确知道要解码字符串类型的返回值。 - 解码响应数据:通过
FunctionDecoder.decodeFunctionResult解析ABI编码的原始响应,得到可读的URI字符串。 - 动态传入tokenID:将tokenID作为函数参数,方便查询任意ID的NFT。
- 完善错误处理:检查响应状态码、捕获异常,给状态赋值明确的错误提示,便于排查问题。
- 简化EthCall构造:静态调用
tokenURI无需签名,createEthCallTransaction的from参数可传null。 - 连接失败反馈:Web3j创建失败时直接更新状态,避免无意义的后续执行。
后续操作
拿到tokenURI后,可通过HTTP请求(如OkHttp、Retrofit)获取对应的JSON元数据,从中提取图片URL、NFT属性等信息。
内容的提问来源于stack exchange,提问作者Vando
相关产品推荐
相关产品推荐

