You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过钱包地址和代币地址获取余额?Solidity合约调用报错求助

解决调用ERC20 balanceOf时的VM revert错误

可能的错误原因

  • 传入的代币地址无效:要么是外部账户(EOA)而非合约地址,要么合约未实现标准ERC20的balanceOf方法,甚至部分非标准/恶意合约会在balanceOf调用时主动触发revert。
  • 测试环境不匹配:你在Truffle本地测试链(如Ganache)中调用了主网代币地址,但这些代币合约并未部署在本地链上,调用不存在的合约方法会直接触发revert。

排查与解决方案

1. 验证代币地址有效性

先确认TOKENS数组中的地址是合规的ERC20合约:

  • 主网环境下,通过区块浏览器查看地址是否有合约代码,且包含balanceOf(address) returns(uint256)的标准方法签名。
  • 本地测试时,必须先将目标代币合约部署到测试链,再使用部署后的地址进行测试。

2. 添加错误处理(避免单个代币失败导致全局revert)

原代码中只要有一个代币调用失败,整个函数就会revert。可以通过Solidity的try/catch语法处理单个代币的调用异常,保留有效结果:

优化后的合约代码:

pragma solidity ^0.8.17;

import {IERC20} from './IERC20.sol';

contract UtilityContract {
    function getBalances(address walletAddress, address[] memory tokenAddresses) public view returns (address[] memory, uint[] memory, bool[] memory) {
        uint len = tokenAddresses.length;
        uint[] memory balances = new uint256[](len);
        bool[] memory success = new bool[](len); // 标记每个代币的获取状态

        for (uint i=0; i<len; i++) {
            try IERC20(tokenAddresses[i]).balanceOf(walletAddress) returns (uint256 balance) {
                balances[i] = balance;
                success[i] = true;
            } catch {
                balances[i] = 0;
                success[i] = false;
            }
        }
        return (tokenAddresses, balances, success);
    }
}

3. 适配本地测试环境

如果是本地测试,需要先部署测试用ERC20合约,并给目标地址转账后再测试:

修改后的测试代码示例:

const UtilityContract = artifacts.require('UtilityContract');
const ERC20 = artifacts.require('ERC20'); // 引入标准ERC20合约模板

contract('UtilityContract', async (accounts) => {
    it('getBalances', async () => {
        // 部署两个测试代币
        const token1 = await ERC20.new("Token1", "T1", 18);
        const token2 = await ERC20.new("Token2", "T2", 18);
        
        // 给目标地址转入测试代币
        await token1.transfer("0xF977814e90dA44bFA03b6295A0616a897441aceC", web3.utils.toWei("100"));
        await token2.transfer("0xF977814e90dA44bFA03b6295A0616a897441aceC", web3.utils.toWei("200"));

        const utilityContract = await UtilityContract.new();
        const output = await utilityContract.getBalances("0xF977814e90dA44bFA03b6295A0616a897441aceC", [token1.address, token2.address]);
        console.log("代币地址:", output[0]);
        console.log("余额:", output[1].map(b => web3.utils.fromWei(b)));
        console.log("获取状态:", output[2]);
    });
});

4. 确认IERC20接口正确性

确保你的IERC20.sol是标准ERC20接口,避免因方法签名错误导致调用失败:

pragma solidity ^0.8.17;

interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

内容的提问来源于stack exchange,提问作者Linus Tan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 14:01:38