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.

Introduction

Glad to have you back for the second instalment of the Foundry Series. In the first article, Foundry vs Hardhat, 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? vm prank Foundry is the pattern of impersonating any caller in tests using vm.prank so you can validate access control and msg.sender-dependent flows, an essential part of any smart contract audit. For advanced Foundry Solidity setups, it’s the fastest way to reproduce real-world caller contexts, multi-sig paths, and meta-tx routes.

What Is vm.prank and Why It Matters

In short, vm prank Foundry lets you spoof any msg.sender to validate permissioned logic without boilerplate.

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, common in DAO governance admin flows, you can prank a non-owner and verify it fails. In Foundry’s forge-stdTest 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

In advanced Foundry Solidity, vm.startPrank mirrors realistic batched execution and relayed flows. For advanced Foundry Solidity cases, vm.startPrank persists impersonation across multi-call sequences and reentrancy paths. 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)

Pair vm prank Foundry with assertions to lock expectations for admins, multisigs, EOAs, and relayers.

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, especially useful when those calls cross protocol boundaries, where an Ecosystem Risk Assessment can surface hidden dependencies. A new cheat-code post will land each day until we’ve worked through the full set.

Conclusion

Use vm prank Foundry to impersonate callers and prove access control with confidence. For advanced Foundry Solidity, lean on vm.startPrank for multi-step flows, then lock behavior with assertion cheatcodes and clear teardown between cases.

Frequently Asked Questions (FAQ)

What is vm prank Foundry and when should I use it?

vm prank Foundry is a testing pattern that uses vm.prank(address) to impersonate any caller for the next call. It’s ideal for verifying access control, role-gated flows (admin, guardian, multisig), and msg.sender dependent logic like allowlists or fee exemptions, core needs in advanced Foundry Solidity test suites.

How do vm.prank, vm.startPrank/stopPrank, and hoax differ?

- vm.prank(addr): switch msg.sender for one call.

-vm.startPrank(addr) / vm.stopPrank(): persist impersonation across multiple calls (great for multi-step workflows, proxies, or reentrancy tests).

- hoax(addr, value?): fund the account (optional) and impersonate for a single call (also sets tx.origin = addr). Use startPrank for complex sequences; use hoax when you need funds and a one-shot impersonation.

How do I avoid flaky tests when using vm prank Foundry in advanced Foundry Solidity setups?

Keep impersonation scoped (always call vm.stopPrank()), reset state between tests, and assert both success and revert paths. For batched or proxy flows, prefer vm.startPrank so every internal call shares the same msg.sender. Pair with helpers like deal() to fund accounts, and log addresses on failure to catch leaked pranks early.

Simeon Cholakov
Simeon Cholakov

Security Researcher