> ## 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 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);
}
```

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);
```

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

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.
