Я пытаюсь смоделировать изменение баланса токенов ERC20, используя функцию Ethereum State Override. Я внедрил код контракта токена в EVM и использовал State Override для изменения баланса целевой учетной записи. Однако результат запроса баланса целевой учетной записи всегда возвращает 0, независимо от того, как я настраиваю свой код.
Я пробовал разные методы, в том числе использовал другой поддельный код, модифицировал разные переменные состояния и т. д. Однако результат всегда неверен.
Я хотел бы знать, где я ошибаюсь, или есть ли другой способ использовать State Override для имитации изменения баланса токена ERC20?
Я пробовал использовать следующий код с изменением баланса USDT, но не работал:
(async () => {
const Web3 = require('web3');
const web3 = new Web3('http://192.168.50.159:7546');
const targetAddress = '0xb7BF3e961645b8ebB75A622A07983335B61cf5c0'; // replace with the target account address
const usdtContractAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7'; // USDT contract address
const fakeUsdtCode = '0x606060405260008054600160a060020a03191673ffffffffffffffffffffffffffffffffffffffff9091169150506103c3806100516000396000f3';
const fakeUsdtBalance = '0x00000000000000000000000000000000000000000000000000000000000000ff'; // set the fake USDT balance to 255
const result = await web3.eth.call({
to: usdtContractAddress,
data: '0x70a08231000000000000000000000000' + targetAddress.substring(2), // USDT balanceOf() function
stateOverride: {
account: targetAddress,
code: fakeUsdtCode,
storage: {
[web3.utils.sha3('balances(' + targetAddress + ')')]: fakeUsdtBalance
}
}
});
console.info('USDT balance of ' + targetAddress + ': ' + web3.utils.hexToNumberString(result));
})()
web3.eth.call
не поддерживает параметры переопределения состояния.Средство форматирования аргумента eth_call
игнорирует поле stateOverride
. Вы можете расширить web3.eth
и вызвать метод RPC вручную:
web3.eth.extend({
methods: [
{
name: 'callWithState',
call: 'eth_call',
params: 3,
}
]
});
eth_call
структура переопределения состояния json недействительна, должно быть:const stateOverride = {
[usdtContractAddress]: {
stateDiff: {
[mappingSlot]: fakeUsdtBalance,
}
}
}
Вы должны принять во внимание номер слота. Вы вычисляете его из исходного кода: https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code Переменная состояния balances
имеет номер слота - 2
. (Я написал статью о слотах и хранилище простое-глубокое-погружение-в-evm-хранилище)
Правильный расчет слота будет:
let mValue = web3.eth.abi.encodeParameters (['address', 'uint256'], [targetAddress, 2]);
let mSlot = web3.utils.keccak256(mValue)
Geth выдает исключение: stack underflow (2 <=> 3)
Подводя итог коду:
web3.eth.extend({
methods: [
{
name: 'callWithState',
call: 'eth_call',
params: 3,
}
]
});
const targetAddress = '0xb7BF3e961645b8ebB75A622A07983335B61cf5c0';
const usdtContractAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7';
const fakeUsdtCode = '0x606060405260008054600160a060020a03191673ffffffffffffffffffffffffffffffffffffffff9091169150506103c3806100516000396000f3';
const fakeUsdtBalance = '0x00000000000000000000000000000000000000000000000000000000000000ff';
const mValue = web3.eth.abi.encodeParameters(['address', 'uint256'], [targetAddress, 2]);
const mSlot = web3.utils.keccak256(mValue)
const callParams = {
to: usdtContractAddress,
data: '0x70a08231000000000000000000000000' + targetAddress.substring(2),
};
const stateDiff = {
[usdtContractAddress]: {
//code: fakeUsdtCode,
stateDiff: {
[mSlot]: fakeUsdtBalance,
},
}
};
const result = await web3.eth.callWithState(callParams, 'latest', stateDiff);
console.info(`USDT balance: ${result}`);
//> USDT balance: 0x00000000000000000000000000000000000000000000000000000000000000ff