10x Solidity Development using Foundry

Rahul Ravindran

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. Foundry is consistently 1.5x-11x faster than Hardhat.

Installation

Using foundryup

The easiest way to get Foundry is to install the latest release by using foundryup.

On Linux and macOS systems, this is done as follows:

curl -L https://foundry.paradigm.xyz | bash

This will download foundryup. To start install Foundry, run:

foundryup

If everything goes well, you will now have two binaries at your disposal: forge and cast.

On Windows, build from source.

Running foundryup again will update to the latest Foundry release. You can also revert to a specific version of Foundry with foundryup -v $VERSION.

Building from source

To build from source, you need to get Rust and Cargo. The easiest way to get both is by using rustup.

On Linux and macOS systems, this is done as follows:

curl https://sh.rustup.rs -sSf | sh

It will download a script and start installation.

On Windows, download and run rustup-init from rustup.rs. It will start the installation in a console.

After this, run the following to build Foundry from source:

cargo install --git https://github.com/gakonst/foundry --bins --locked

Using with Docker

Foundry can also be used entirely within a Docker container. If you don’t have it, Docker can be installed directly from Docker’s website

Once installed, you can download the latest release by running:

docker pull ghcr.io/gakonst/foundry:latest

It is also possible to build the docker image locally. From the Foundry repository, run:

docker build -t foundry .

ℹ️ Note

Some machines (including those with M1 chips) may be unable to build the docker image locally. This is a known issue.

Creating a new project

To start a new project with Foundry, use forge init:

{{#include ../output/hello_foundry/forge-init:command}}

This creates a new directory hello_foundry from the default template. This also initializes a new git repository.

If you want to create a new project using a different template, you would pass the --template flag, like so:

$ forge init --template https://github.com/FrankieIsLost/forge-template hello_template

For now, let’s check what the default template looks like:

$ cd hello_foundry
{{#include ../output/hello_foundry/tree:all}}

The default template comes with one dependency installed: ds-test. This is the preferred assertion library used for Foundry projects. Additionally, the template also comes with an empty starter contract and a simple test.

Let’s build the project:

{{#include ../output/hello_foundry/forge-build:all}}

And run the tests:

{{#include ../output/hello_foundry/forge-test:all}}

You’ll notice that two new directories have popped up: out and cache.

The out directory contains your contract artifact, such as the ABI, while the cache is used by forge to only recompile what is necessary.

Project Layout

Forge is flexible on how you structure your project. By default, the structure is:

{{#include ../output/hello_foundry/tree-with-files:output}}
  • You can configure Foundry’s behavior using foundry.toml.
  • Remappings are specified in remappings.txt.
  • The default directory for contracts is src/.
  • The default directory for tests is src/test/, where any contract with a function that starts with test is considered to be a test.
  • Dependencies are stored as git submodules in lib/.

You can configure where Forge looks for both dependencies and contracts using the --lib-paths and --contracts flags respectively. Alternatively you can configure it in foundry.toml.

Combined with remappings, this gives you the flexibility needed to support the project structure of other toolchains such as Hardhat and Truffle.

For automatic Hardhat support you can also pass the --hh flag, which sets the following flags: --lib-paths node_modules --contracts contracts.

Writing Tests

Forge can run your tests with the forge test command. All tests are written in Solidity.

Forge will look for the tests anywhere in your source directory. Any contract with a function that starts with test is considered to be a test. Usually, tests will be placed in src/test by convention and end with .t.sol.

Here’s an example of running forge test in a freshly created project, that only has the default test:

{{#include ../output/hello_foundry/forge-test:all}}

You can also run specific tests by passing a filter:

{{#include ../output/test_filters/forge-test-match-contract-and-test:all}}

This will run the tests in the ComplicatedContractTest test contract with testDeposit in the name. Inverse versions of these flags also exist (--no-match-contract and --no-match-test).

You can run tests in filenames that match a regex with --match-path.

{{#include ../output/test_filters/forge-test-match-path:all}}

The inverse of the --match-path flag is --no-match-path.

Logs and traces

The default behavior for forge test is to only display a summary of passing and failing tests. You can control this behavior by increasing the verbosity (using the -v flag). Each level of verbosity adds more information:

  • Level 2 (-vv): Logs emitted during tests are also displayed.
  • Level 3 (-vvv): Stack traces for failing tests are also displayed.
  • Level 4 (-vvvv): Stack traces for all tests are displayed, and setup traces for failing tests are displayed.
  • Level 5 (-vvvvv): Stack traces and setup traces are always displayed.
Framework Remote RPC Local RPC Cached
Blocknative N/A N/A 0m3.529s
Dapptools 52m17.447s 17m34.869s 3m25.896s
Ganache 10m5.384s 1m2.275s 0m22.662s
Hardhat 8m26.483s 0m35.145s 0m7.531s
Foundry 6m59.875s 0m13.610s 0m0.537s
Tenderly N/A N/A 0m1.9315s

Cast tool

cast is Foundry’s command-line tool for performing Ethereum RPC calls. You can make smart contract calls, send transactions, or retrieve any type of chain data – all from your command-line!

How to use cast

To use cast, use the cast keyword followed by a subcommand:

$ cast <subcommand>

Examples

Let’s use cast to retrieve the total supply of the DAI token:

{{#include ../output/cast/cast-call:all}}

cast also provides many convenient subcommands, such as for decoding calldata:

{{#include ../output/cast/cast-4byte-decode:all}}

Conclusion

Foundry is an exceptionally fast developer toolkit for EVM based blockchains. You should definitely use it to fastrack your development process.

0 Comments

Leave a Reply

More great articles

Getting Started With Ganache V7

Intro OK developers welcome back! In this video I think it's time for us to revisit Ganache. Ganache is part…

Read Story

Set up your own Ethereum Node using Geth

Geth (short for Go Ethereum) is one of the three original implementations (along with C++ and Python) of the Ethereum…

Read Story

Smart Contract Security Roadmap

In 2021 $1.5 billion were hacked from smart contracts. That’s why smart contract security experts are in high demand and…

Read Story

Never miss a minute

Get great content to your inbox every week. No spam.
[contact-form-7 id="6" title="Footer CTA Subscribe Form"]
Arrow-up