Every Virtual Environment exposes a precompile contract at 0xc100000000000000000000000000000000000000. Calling functions on this precompile from inside a transaction lets your contracts manipulate on-chain state directly, storage slots, balances, nonces, and event logs, without impersonating accounts or deploying helper proxies.
These cheatcodes complement the Admin RPC methods. The Admin RPC methods manipulate state from outside a transaction (via JSON-RPC). The precompile manipulates state from inside a transaction (via Solidity call). Use the precompile when your setup needs to stay atomic, be replayable from a tx hash, or run in a loop over many slots.
Interface
Add this file to your project as 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);
}
Reference it in your contract at the fixed address:
IVnetPrecompile constant VNET = IVnetPrecompile(0xc100000000000000000000000000000000000000);
Functions
Storage
| Function | Parameters | Returns | Description |
|---|
setStorageAt | address target, bytes32 slot, bytes32 value | bool | Writes value to slot on target. |
getStorageAt | address target, bytes32 slot | bytes32 | Reads the current value of slot on target. |
VNET.setStorageAt(tokenContract, balanceSlot, bytes32(uint256(1000e18)));
bytes32 val = VNET.getStorageAt(tokenContract, balanceSlot);
Balance
| Function | Parameters | Returns | Description |
|---|
setBalance | address target, uint256 balance | bool | Sets the ETH balance of target to an exact value. |
addBalance | address target, uint256 amount | bool | Adds amount to the current ETH balance of target. |
VNET.setBalance(account, 10 ether);
VNET.addBalance(account, 2 ether);
Nonce
| Function | Parameters | Returns | Description |
|---|
setNonce | address target, uint256 value | bool | Sets the transaction count of target. |
VNET.setNonce(account, 42);
Events
emitEvent fires a log whose address field is target, not the calling contract. Downstream consumers (indexers, subgraphs, webhooks) treat the log as a real emission from target.
Nine overloads cover zero to four indexed topics with an optional unindexed data payload:
| Overload | Topics | Data |
|---|
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 is typically keccak256("EventName(type,type,...)"). Example, spoof a USDC Transfer:
VNET.emitEvent(
USDC,
keccak256("Transfer(address,address,uint256)"),
bytes32(uint256(uint160(from))),
bytes32(uint256(uint160(to))),
abi.encode(amount)
);
The precompile also emits its own diagnostic logs (balance set, nonce set, storage written) with address = 0xc100000000000000000000000000000000000000. When inspecting a receipt for a spoofed log, filter logs[] by the target address to ignore the precompile’s own entries.
Known limitations
- Arbitrum-based Virtual Environments. Cheatcode calls made through
eth_call do not work because the precompile is not registered at the Nitro layer. Transactions, gas estimates, and simulations work as expected.
See also
- Admin RPC, the equivalent JSON-RPC methods for state manipulation from outside a transaction.
- Foundry cheatcode tutorial, end-to-end walkthrough deploying a reusable cheatcode playground.