# Foundry–Polkadot: Testing Directly in pallet-revive

**URL:** <https://forum.polkadot.network/t/foundry-polkadot-testing-directly-in-pallet-revive/17103>\
**Category:** Tech Talk\
**Created:** [February 16, 2026, 12:18pm UTC](https://forum.polkadot.network/t/foundry-polkadot-testing-directly-in-pallet-revive/17103 "2026-02-16T12:18:22Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![smiasojed](https://dub1.discourse-cdn.com/flex005/user_avatar/forum.polkadot.network/smiasojed/32/2667_2.png) [@smiasojed](https://forum.polkadot.network/u/smiasojed)\
**Post date:** [February 16, 2026, 12:18pm UTC](https://forum.polkadot.network/t/foundry-polkadot-testing-directly-in-pallet-revive/17103/1 "2026-02-16T12:18:22Z")

</div>

# Foundry–Polkadot: Testing Directly in pallet-revive

[Foundry–Polkadot v1.5.1](https://github.com/paritytech/foundry-polkadot/releases/tag/v1.5.1) is out with two major features:

- **pallet-revive testing** — `forge test --polkadot` now executes contracts directly inside pallet-revive, supporting both EVM and PolkaVM (RISC-V) backends.
- **anvil-polkadot** — a Substrate-based local node with an Ethereum-compatible RPC API.

This document covers the testing integration.

## Pallet-revive Architecture

Pallet-revive supports two execution backends:

| Bytecode | VM | Description |
| --- | --- | --- |
| **EVM** | EVM Interpreter | Executes EVM bytecode inside the REVM interpreter. |
| **PVM** | PolkaVM (RISC-V) | Executes PVM bytecode inside the PolkaVM interpreter. |

Developers can compile a single Solidity source into both bytecode formats. The bytecode deployed determines which backend executes it.

## How It Works

In standard Foundry, all contracts execute inside **Foundry EVM**. In Foundry-Polkadot, the test contract still runs in Foundry EVM, but contract deployment and calls are **intercepted** and routed to **pallet-revive** :

| Opcode | Behaviour |
| --- | --- |
| `CREATE` / `CREATE2` | Contract deployed inside pallet-revive instead of Foundry EVM. |
| `CALL` / `STATICCALL` / `DELEGATECALL` | Call executed inside pallet-revive instead of Foundry EVM. |

This means:

- Test logic, assertions, and cheatcodes run in Foundry EVM as usual.
- Contract execution happens inside pallet-revive.
- State is synchronised between the two environments using **diff-based bridging** - changed storage slots are synced after each call, keeping cheatcodes like `vm.store` working correctly.

## CLI

```bash
forge test # Standard Foundry behaviour (Foundry EVM)
forge test --polkadot # pallet-revive with EVM backend (default)
forge test --polkadot=evm # Same as above, explicit
forge test --polkadot=pvm # pallet-revive with PVM backend (experimental)

```

## Switching Backends: `vm.polkadot`

Within a test, you can switch where contracts are deployed and executed using the `vm.polkadot` cheatcode - for example, to compare contract behaviour across backends or to deploy specific contracts in Foundry EVM instead of pallet-revive.

```solidity
interface Vm {
    /// Switch INTO or OUT OF Polkadot runtime (pallet-revive).
    /// backend: "evm", or "pvm"
    function polkadot(bool enable, string calldata backend) external;

    /// Auto-detect backend from CLI flags.
    function polkadot(bool enable) external;
}

```

> **Note** : Contracts must be registered with `vm.makePersistent` to survive backend switches.

## Execution Matrix

The following table describes how CLI flags interact with cheatcodes in different scenarios.

### Scenario 1: Standard Foundry EVM

**Command:** `forge test`  
**Context:** The test runs entirely in Foundry EVM. Polkadot features are disabled.

| Cheatcode Action | Resulting Environment |
| --- | --- |
| None | Foundry EVM |
| `vm.polkadot(true)` | ❌ _Invalid (Mode not enabled)_ |

### Scenario 2: Polkadot EVM

**Command:** `forge test --polkadot=evm` or `forge test --polkadot`  
**Context:** The test runs in Polkadot mode, deploying **EVM bytecode** by default to pallet-revive. You can switch back to Foundry EVM deployment.

| Cheatcode Action | Resulting Environment |
| --- | --- |
| None | Polkadot EVM |
| `vm.polkadot(false)` | Foundry EVM |
| `vm.polkadot(true, "pvm")` | ❌ _Not supported - contracts are not compiled to PVM in EVM mode_ |

### Scenario 3: Polkadot PVM

**Command:** `forge test --polkadot=pvm`  
**Context:** The test runs in Polkadot mode, deploying **PVM bytecode** to pallet-revive. Both EVM and PVM bytecodes are compiled, so you can switch between backends.

| Cheatcode Action | Resulting Environment |
| --- | --- |
| None | Polkadot PVM |
| `vm.polkadot(false)` | Foundry EVM |
| `vm.polkadot(true, "evm")` | Polkadot EVM |

## Example

```solidity
contract Simple {
    function get() public pure returns (uint256) {
        return 6;
    }
}

contract FooTest is Test {
    function testSimple() public {
        // Deploy: intercepted → deployed to pallet-revive
        Simple testContract = new Simple();

        // Call: intercepted → executed in pallet-revive
        uint256 number = testContract.get();

        // Assert: runs in Foundry EVM
        assertEq(6, number);
    }
}

```

**Execution flow with `forge test --polkadot` (Default: EVM Backend):**

1. The test starts in Foundry EVM.
2. `new Simple()` is identified as a `CREATE` opcode. The system intercepts it and deploys the contract into **pallet-revive**.
3. `testContract.get()` is identified as a `CALL`. It is executed in **pallet-revive**.
4. The return value `6` is passed back to the test runner.
5. `assertEq` runs in Foundry EVM to verify the result.

## Limitations

Tests on standard open-source projects show a **90–100% pass rate** with the Polkadot EVM backend. Known limitations:

1. **Gas model** — Not fully aligned with Polkadot’s production gas model. Tests relying on precise gas checks may fail.
2. **Numeric types** — Ethereum uses `u256` for balances, block numbers, and timestamps. Polkadot uses `u128` for balances and `u64` for block numbers/timestamps. Values exceeding these limits are clamped with a warning.
3. **PVM backend maturity** — The PVM backend is experimental. Tests may fail when using libraries or proxy patterns.
