# Foundry: forge, cast and anvil — Blockchain & Smart Contracts (Solidity)

Source: https://www.geekswithgeeks.com/en/solidity/w-foundry

> Build, test and script contracts with Foundry.

## A fast, Solidity-native toolkit

**Foundry** is a popular Rust-based toolkit for Solidity development. **`forge`** builds, tests and deploys: tests are written **in Solidity** in `test/`, in contracts inheriting `forge-std/Test.sol`, with functions starting `test` (and `testFuzz` style parameters for fuzzing). **Cheatcodes** on the `vm` object control the environment: `vm.prank(addr)` sets `msg.sender` for the next call, `vm.deal` sets balances, `vm.warp` changes `block.timestamp`, `vm.roll` changes block numbers, `vm.expectRevert` and `vm.expectEmit` assert reverts and events, and `makeAddr` creates labelled addresses. `forge test -vvvv` shows detailed traces, `forge coverage` reports coverage and `forge snapshot` tracks gas. **Mainnet forking** (`--fork-url`) runs tests against real deployed contracts and state. **`cast`** is a command-line Swiss army knife for calling contracts, sending transactions, decoding calldata and converting units. **`anvil`** runs a local Ethereum node with funded test accounts. **Solidity scripts** (`forge script`) deploy contracts reproducibly. Dependencies are installed as git submodules or via Soldeer, and import remappings map paths such as `@openzeppelin/`.

## The Foundry toolkit

forge builds and tests, cast talks to chains, anvil runs a local node.

![Three tool icons on a workbench, a hammer, a fishing line and an anvil, each connected to a small blockchain icon.](assets/figures/solidity/section-7-map.svg) — Figure 7.1 — forge, cast and anvil.

## Foundry workflow and a unit test with cheatcodes

Time travel, pranks and event assertions.

```solidity
// test/PiggyBank.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Test} from "forge-std/Test.sol";
import {PiggyBank} from "../src/PiggyBank.sol";

contract PiggyBankTest is Test {
    PiggyBank bank;
    address owner = makeAddr("owner");
    address saver = makeAddr("saver");

    event Deposited(address indexed from, uint256 amount);

    function setUp() public {
        vm.prank(owner);
        bank = new PiggyBank(7 days);
        vm.deal(saver, 5 ether);
    }

    function test_DepositEmitsEvent() public {
        vm.expectEmit(true, false, false, true);
        emit Deposited(saver, 1 ether);
        vm.prank(saver);
        bank.deposit{value: 1 ether}();
    }

    function test_CannotWithdrawBeforeUnlock() public {
        uint256 unlock = bank.unlockTime();           // read before prank/expectRevert
        vm.prank(owner);
        vm.expectRevert(abi.encodeWithSelector(PiggyBank.Locked.selector, unlock));
        bank.withdrawAll();
    }

    function test_WithdrawAfterUnlock() public {
        vm.prank(saver);
        bank.deposit{value: 2 ether}();
        vm.warp(block.timestamp + 7 days);             // time travel
        vm.prank(owner);
        bank.withdrawAll();
        assertEq(owner.balance, 2 ether);
    }
}

// Shell:
//   forge init piggy && cd piggy
//   forge test -vvv
//   anvil                                   # local node with funded accounts
//   cast balance <address> --rpc-url http://127.0.0.1:8545
```

## Fork tests for integrations

If your contract talks to a real DEX, oracle or token, fork mainnet or a testnet in your tests. Mocks rarely reproduce the quirks of the real contracts you integrate with.

**Quiz:** What does vm.prank(addr) do in a Foundry test?

- [x] Makes the next call come from addr, setting msg.sender
- [ ] Deletes an address
- [ ] Gives addr ether
- [ ] Advances time

*Answer:* Makes the next call come from addr, setting msg.sender. prank changes msg.sender for the next external call.
