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

使用Ethereum State Override模拟修改ERC20代币余额失败求助

问题诊断与解决方案

你的代码存在三个核心问题,导致余额始终返回0:

1. State Override 目标账户错误

ERC20的balances映射存储在代币合约的账户状态中,而非用户地址的状态里。你当前覆盖的是目标用户地址的状态,完全没触及USDT合约的存储,所以读取的还是原合约的真实余额(0)。

2. 存储槽计算方式错误

Solidity中mapping(address => uint256)类型的存储槽计算规则是:
keccak256(abi.encodePacked(用户地址, 映射变量的存储槽索引))
USDT合约中balances是第一个状态变量,存储槽索引为0。你用字符串拼接的方式计算哈希,完全不符合Solidity的存储布局规则,导致找不到正确的存储位置。

3. 不必要的假合约代码

你注入的fakeUsdtCode是一个没有实现balanceOf方法的空合约,即使覆盖存储,调用该方法也会返回默认值0。实际上不需要替换合约代码,直接覆盖原合约的存储即可。


修正后的代码

(async () => {
    const Web3 = require('web3');
    const web3 = new Web3('http://192.168.50.159:7546'); 

    const targetAddress = '0xb7BF3e961645b8ebB75A622A07983335B61cf5c0';
    const usdtContractAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7';
    const fakeUsdtBalance = '0x00000000000000000000000000000000000000000000000000000000000000ff'; // 255

    // 正确计算balances映射的存储槽
    const storageKey = web3.utils.soliditySha3(
        { type: 'address', value: targetAddress },
        { type: 'uint256', value: 0 } // balances的存储槽索引为0
    );

    const result = await web3.eth.call({
        to: usdtContractAddress,
        data: '0x70a08231000000000000000000000000' + targetAddress.substring(2),
        stateOverride: {
            // 覆盖USDT合约的状态,而非用户地址
            [usdtContractAddress]: {
                storage: {
                    [storageKey]: fakeUsdtBalance
                }
            }
        }
    });

    console.log(`${targetAddress}的USDT余额: ${web3.utils.hexToNumberString(result)}`);
})();

其他实现方法

如果State Override的方式不符合需求,还可以:

  • 部署一个自定义的ERC20测试合约,在测试环境中直接调用_mint方法生成余额
  • 使用Hardhat的impersonateAccount功能,模拟持有大额余额的账户(适合测试交互场景)

内容的提问来源于stack exchange,提问作者Moon soon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:22:41