Перейти к основному содержанию
Каждая Virtual Environment предоставляет прекомпайл-контракт по адресу 0xc100000000000000000000000000000000000000. Вызов функций этого прекомпайла изнутри транзакции позволяет вашим контрактам напрямую манипулировать состоянием on-chain — слотами хранилища, балансами, nonce и логами событий — без имперсонации аккаунтов и деплоя вспомогательных прокси. Эти чит-коды дополняют методы Admin RPC. Методы Admin RPC манипулируют состоянием извне транзакции (через JSON-RPC). Прекомпайл манипулирует состоянием изнутри транзакции (через Solidity-вызов). Используйте прекомпайл, когда ваш сетап должен оставаться атомарным, быть воспроизводимым по хешу транзакции или выполняться в цикле по многим слотам.

Интерфейс

Добавьте этот файл в ваш проект как IVnetPrecompile.sol:
IVnetPrecompile.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IVnetPrecompile {
    function setStorageAt(address target, bytes32 slot, bytes32 value) external returns (bool);
    function getStorageAt(address target, bytes32 slot) external view returns (bytes32);
    function setBalance(address target, uint256 balance) external returns (bool);
    function addBalance(address target, uint256 amount) external returns (bool);
    function setNonce(address target, uint256 value) external returns (bool);

    function emitEvent(address target, bytes calldata data) external returns (bool);
    function emitEvent(address target, bytes32 topic1) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes calldata data) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2, bytes calldata data) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2, bytes32 topic3) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes calldata data) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4) external returns (bool);
    function emitEvent(address target, bytes32 topic1, bytes32 topic2, bytes32 topic3, bytes32 topic4, bytes calldata data) external returns (bool);
}
Ссылайтесь на него в вашем контракте по фиксированному адресу:
IVnetPrecompile constant VNET = IVnetPrecompile(0xc100000000000000000000000000000000000000);

Функции

Хранилище

ФункцияПараметрыВозвращаетОписание
setStorageAtaddress target, bytes32 slot, bytes32 valueboolЗаписывает value в slot на target.
getStorageAtaddress target, bytes32 slotbytes32Читает текущее значение slot на target.
VNET.setStorageAt(tokenContract, balanceSlot, bytes32(uint256(1000e18)));
bytes32 val = VNET.getStorageAt(tokenContract, balanceSlot);

Баланс

ФункцияПараметрыВозвращаетОписание
setBalanceaddress target, uint256 balanceboolУстанавливает ETH-баланс target в точное значение.
addBalanceaddress target, uint256 amountboolДобавляет amount к текущему ETH-балансу target.
VNET.setBalance(account, 10 ether);
VNET.addBalance(account, 2 ether);

Nonce

ФункцияПараметрыВозвращаетОписание
setNonceaddress target, uint256 valueboolЗадаёт счётчик транзакций для target.
VNET.setNonce(account, 42);

События

emitEvent эмитирует лог, у которого поле address — это target, а не вызывающий контракт. Нижестоящие потребители (индексеры, subgraphs, вебхуки) считают лог реальной эмиссией от target. Девять перегрузок покрывают от нуля до четырёх индексируемых топиков с необязательным неиндексируемым data-payload:
ПерегрузкаТопикиДанные
emitEvent(target, data)0
emitEvent(target, t1)1,
emitEvent(target, t1, data)1
emitEvent(target, t1, t2)2,
emitEvent(target, t1, t2, data)2
emitEvent(target, t1, t2, t3)3,
emitEvent(target, t1, t2, t3, data)3
emitEvent(target, t1, t2, t3, t4)4,
emitEvent(target, t1, t2, t3, t4, data)4
topic1 обычно равен keccak256("EventName(type,type,...)"). Пример, подделываем Transfer для USDC:
VNET.emitEvent(
    USDC,
    keccak256("Transfer(address,address,uint256)"),
    bytes32(uint256(uint160(from))),
    bytes32(uint256(uint160(to))),
    abi.encode(amount)
);
Прекомпайл также эмитирует собственные диагностические логи (установка баланса, установка nonce, запись в хранилище) с address = 0xc100000000000000000000000000000000000000. При проверке чека транзакции на предмет подделанного лога фильтруйте logs[] по целевому адресу, чтобы игнорировать собственные записи прекомпайла.

Известные ограничения

  • Virtual Environments на основе Arbitrum. Вызовы чит-кодов через eth_call не работают из-за внутренних особенностей Arbitrum. Транзакции, оценка газа и симуляции работают как ожидается.

См. также

  • Admin RPC — эквивалентные JSON-RPC методы для манипуляции состоянием извне транзакции.
  • Туториал по чит-кодам в Foundry — сквозное прохождение с деплоем переиспользуемой песочницы чит-кодов.