> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Solidity Cheatcodes

> IVnetPrecompile interface reference for the Solidity-level cheatcodes available on every Virtual Environment at 0xc100000000000000000000000000000000000000.

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, ETH balances, ERC-20 token balances, nonces, and event logs, without impersonating accounts or deploying helper proxies.

These cheatcodes complement the [Admin RPC methods](/virtual-environments/admin-rpc). 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`:

```solidity title="IVnetPrecompile.sol" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IVnetPrecompile {
    function setStorageAt(address target, bytes32 slot, bytes32 value) external returns (bool);
    function setBalance(address[] calldata addresses, uint256 balance) external returns (bool);
    function getStorageAt(address target, bytes32 slot) external view returns (bytes32);
    function addBalance(address[] calldata addresses, uint256 amount) external returns (bool);
    function setNonce(address target, uint256 value) external returns (bool);
    function setErc20Balance(address target, address[] calldata addresses, uint256 amount) external returns (bool);
    function addErc20Balance(address target, address[] calldata addresses, uint256 amount) external returns (bool);
    function setMaxErc20Balance(address target, address account) external returns (bool);
    function setCode(address target, bytes calldata code) 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);

    event SetStorageAtEvent(address target, bytes32 slot, bytes32 value);
    event SetBalanceEvent(address[] addresses, uint256 balance);
    event AddBalanceEvent(address[] addresses, uint256 amount);
    event SetNonceEvent(address target, uint256 value);
    event SetErc20BalanceEvent(address target, address[] addresses, uint256 amount);
    event AddErc20BalanceEvent(address target, address[] addresses, uint256 amount);
    event SetMaxErc20BalanceEvent(address target, address account);
    event SetCodeEvent(address target, bytes bytecode);
}
```

Reference it in your contract at the fixed address:

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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`. |

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
VNET.setStorageAt(tokenContract, balanceSlot, bytes32(uint256(1000e18)));
bytes32 val = VNET.getStorageAt(tokenContract, balanceSlot);
```

### Balance

| Function | Parameters | Returns | Description |
| - | - | - | - |
| `setBalance` | `address[] addresses`, `uint256 balance` | `bool` | Sets the ETH balance of every address in `addresses` to an exact value. |
| `addBalance` | `address[] addresses`, `uint256 amount` | `bool` | Adds `amount` to the current ETH balance of every address in `addresses`. |

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
address[] memory accounts = new address[](2);
accounts[0] = alice;
accounts[1] = bob;
VNET.setBalance(accounts, 10 ether);
VNET.addBalance(accounts, 2 ether);
```

### ERC-20 balances

| Function | Parameters | Returns | Description |
| - | - | - | - |
| `setErc20Balance` | `address target`, `address[] addresses`, `uint256 amount` | `bool` | Sets the balance of every address in `addresses` to `amount` on the ERC-20 token at `target`. |
| `addErc20Balance` | `address target`, `address[] addresses`, `uint256 amount` | `bool` | Adds `amount` to the current token balance of every address in `addresses`. |
| `setMaxErc20Balance` | `address target`, `address account` | `bool` | Sets the token balance of `account` to the maximum value (`2^256 - 1`). |

The precompile locates the token's balance storage slot automatically, so no slot input is required. Standard mapping layouts resolve directly and are cached after the first holder; non-standard layouts are discovered by probing the token's `balanceOf` execution.

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
address[] memory holders = new address[](2);
holders[0] = alice;
holders[1] = bob;
VNET.setErc20Balance(USDC, holders, 1_000_000e6);
VNET.addErc20Balance(USDC, holders, 500e6);
VNET.setMaxErc20Balance(USDC, alice);
```

<Note>
  Tokens that pack extra flags into the balance storage slot report `balanceOf` accordingly. For example, USDC reserves the top bit of the slot, so after `setMaxErc20Balance` its `balanceOf` returns `2^255 - 1`.
</Note>

### Nonce

| Function | Parameters | Returns | Description |
| - | - | - | - |
| `setNonce` | `address target`, `uint256 value` | `bool` | Sets the transaction count of `target`. |

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
VNET.setNonce(account, 42);
```

### Code

| Function | Parameters | Returns | Description |
| - | - | - | - |
| `setCode` | `address target`, `bytes code` | `bool` | Replaces the bytecode of `target`. The account's nonce and storage are left unchanged. |

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
VNET.setCode(target, hex"60806040523480156100105760006000fd5b50");
```

The equivalent JSON-RPC cheatcode is documented in [Bytecode deployment cheatcode](/virtual-environments/develop/bytecode-deployment).

### 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`:

```solidity theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
VNET.emitEvent(
    USDC,
    keccak256("Transfer(address,address,uint256)"),
    bytes32(uint256(uint160(from))),
    bytes32(uint256(uint160(to))),
    abi.encode(amount)
);
```

### Cheatcode events

Every state-changing cheatcode emits a corresponding event from the precompile address (`0xc100000000000000000000000000000000000000`):

| Cheatcode | Event |
| - | - |
| `setStorageAt` | `SetStorageAtEvent(address target, bytes32 slot, bytes32 value)` |
| `setBalance` | `SetBalanceEvent(address[] addresses, uint256 balance)` |
| `addBalance` | `AddBalanceEvent(address[] addresses, uint256 amount)` |
| `setNonce` | `SetNonceEvent(address target, uint256 value)` |
| `setErc20Balance` | `SetErc20BalanceEvent(address target, address[] addresses, uint256 amount)` |
| `addErc20Balance` | `AddErc20BalanceEvent(address target, address[] addresses, uint256 amount)` |
| `setMaxErc20Balance` | `SetMaxErc20BalanceEvent(address target, address account)` |
| `setCode` | `SetCodeEvent(address target, bytes bytecode)` |

When inspecting a receipt for a log spoofed via `emitEvent`, filter `logs[]` by the target address to ignore the precompile's own entries.

## Known limitations

* **Base-based Virtual Environments.** Solidity cheatcodes are not available on Base.
* **Arbitrum-based Virtual Environments.** Cheatcode calls made through `eth_call` do not work due to Arbitrum internals. Transactions, gas estimates, and simulations work as expected.

## See also

* [Admin RPC](/virtual-environments/admin-rpc), the equivalent JSON-RPC methods for state manipulation from outside a transaction.
* [Foundry cheatcode tutorial](/virtual-environments/develop/solidity-cheatcodes), end-to-end walkthrough deploying a reusable cheatcode playground.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.