Blockchain security isn't optional.

Protect your smart contracts and DeFi protocols with Three Sigma, a trusted security partner in blockchain audits, smart contract vulnerability assessments, and Web3 security.

Get a Quote Today

Introduction

Glad to have you back for the second installment of the Foundry Cheatcodes Series. In Part 1 we compared Foundry to Hardhat and laid the foundation for faster, Solidity-native testing; today we zoom in on vm.prank, the trick that lets your tests masquerade as any address to probe access-control edge cases.

Ever needed to test access control or simulate calls from different users? Foundry’s vm.prank makes it dead simple to impersonate any address and validate your contract logic.

What Is vm.prank and Why It Matters

The vm.prank(address) cheatcode makes the next contract call appear to come from a different address (it sets msg.sender). This is essential when testing logic that depends on the caller. For example, if only the owner can call a function, you can prank a non-owner and verify it fails. In Foundry’s forge-std Test contract, you simply do:

image

Here, vm.prank(0xBEEF) forces the next call to c.privileged() to originate from 0xBEEF. Foundry then verifies the revert as expected. Behind the scenes Foundry invokes a special address 0x7109...DD12 to perform the cheat. Any time Solidity code calls that address, Forge’s custom EVM hooks it, decodes the calldata, and routes it to a native Rust handler that mutates the in-memory chain state. No contract is actually deployed, everything happens inside the test runner, so the bytecode stays lean and the cheatcodes disappear in production builds. If you ran the compiled test on mainnet the same call would simply revert, because nothing exists at 0x7109…DD12 outside Forge.

Simulating Multiple Calls with vm.startPrank

For multiple calls, use vm.startPrank(addr) to persist the fake identity across subsequent calls, and end it with vm.stopPrank(). For example:

image

Why Foundry Wins (and What’s Next)

Foundry’s speed, single-language test workflow, and built-in fuzz/invariant engines make it the first tool I reach for when security or deep protocol testing matters. Hardhat’s ecosystem is huge and its JS plugins are handy, but once teams feel the compile-and-test loop drop from seconds to milliseconds, and realise they can ditch TypeScript test harnesses entirely, the switch is hard to undo. Rust-level performance, Solidity-level ergonomics.

In the next installment we’ll keep the cheat-code deep dives rolling: Part 3 tackles the expect-based assertion trio, vm.expectRevert, vm.expectEmit, and vm.expectCall, showing how to lock in reverts, events, and external calls before they happen. A new cheat-code post will land each day until we’ve worked through the full set.

Simeon Cholakov
Simeon Cholakov

Security Researcher