Getting Started with Foundry
Foundry is a smart contract development toolchain, and user-friendly development environment for writing and testing smart contracts in Solidity. It manages dependencies, compiles, run tests, deploy contracts and allows for interaction with EVM-compatible chains using a command-line tool called Forge.
In this guide, we will learn about Foundry and its benefits for smart contract development, how to setup your environment, create a Foundry project and execute a deployment script.
Why use Foundry?
Forge is ideal for advanced smart contract analysis, auditing, and for fast execution of smart contract tests.
Note: Use the hardhat-foundry plugin to have your Foundry project work alongside Hardhat.
Here are some reason why you may prefer Foundry:
- Local Networks:
It provides a local blockchain environment using the anvil tool, allowing developers to deploy contracts, run tests, and debug code. It can also be used to fork other EVM compatible networks.
- Advanced Testing:
Forge comes with a number of advanced testing methods including:
- Fuzz testing
- Invariant testing
- Differential testing
- Symbolic Execution
- Mutation Testing
- Advanced Debugging:
Forge allows for advanced debugging using an interactive debugger.
The debugger terminal is divided into four quadrants:
- Quadrant 1
- The opcodes in the debugging session, with the current opcode highlighted. Additionally, the address of the current account, the program counter and the accumulated gas usage is also displayed.
- Quadrant 2
- The current stack, as well as the size of the stack
- Quadrant 3
- The source view.
- Quadrant 4
-
The current memory of the EVM.
-
Getting Started
Prerequisites
To get started with Foundry, ensure the following tools are installed:
- The Rust Compiler
- Cargo Package Manager
For an easy installation of the above tools, use the rustup installer.
Installation
To install, use Foundryup. Foundryup is the Foundry toolchain installer. You can find more information in the Foundry README.
curl -L https://foundry.paradigm.xyz | bash
Running foundryup by itself will install the latest (nightly) precompiled binaries: forge
, cast
, anvil
, and chisel
.
Visit the installation guides for more information.
Create a foundry project
To start a new project with Foundry, use forge init.
forge init hello_foundry
See more details on how to create a new project using the Foundry guide.
Write your first contract
Let’s view the file structure for a default foundry project:
$ cd hello_foundry
$ tree . -d -L 1
.
├── lib
├── script
├── src
└── test
4 directories
The src
directory contains counter smart contract with test written in the test
directory. Now, let's build the foundry project.
forge build
And then run tests.
forge test
Deploy contract on the Rootstock
To deploy the counter contract on Rootstock mainnet or testnet, further configure Foundry by setting up a Rootstock RPC url and a private key of an account that’s funded with tRBTC.
Environment Configuration
Once you have an account with a private key, create a .env
file in the root of the foundry project and add the variables.
Foundry automatically loads a .env
file present in the project directory.
The .env
file should follow this format:
ROOTSTOCK_RPC_URL=https://public-node.testnet.rsk.co
PRIVATE_KEY=0x...
At the root of the project, run:
# To load the variables in the .env file
source .env
Modify Deployment Script
Modify the deployment counter deploy script in the scripts
directory to use the private key by modifying the run method, see below example:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import {Script, console} from "forge-std/Script.sol";
import "../src/Counter.sol";
contract CounterScript is Script {
function setUp() public {}
function run() public {
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
new Counter();
vm.stopBroadcast();
}
}
By default, scripts are executed by calling the function named run
at the entrypoint.
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
- CAUTION: Be cautious when exposing private keys in a
.env
file and loading them into programs.- This is only recommended for use with non-privileged deployers or for local / test setups.
When calling vm.startBroadcast()
, the contract creation will be recorded by Forge, and we can broadcast the transaction to deploy the contract on-chain.
Execute the deployment script
We will use Forge to run our script and broadcast the transactions - this can take a little while, since Forge also waits for the transaction receipts.
forge script script/Counter.s.sol --rpc-url $ROOTSTOCK_RPC_URL --broadcast --legacy
- Note:
- EIP-1559 is not supported or not activated on the Rootstock RPC url
- The
--legacy
flag is passed to use legacy transactions instead ofEIP-1559
.
The result should look like this:
[⠰] Compiling...
No files changed, compilation skipped
Script ran successfully.
== Logs ==
Counter:
## Setting up 1 EVM.
==========================
Chain 31
Estimated gas price: 0.065164 gwei
Estimated total gas used for script: 138734
Estimated amount required: 0.000009040462376 ETH
==========================
##
Sending transactions [0 - 0].
⠁ [00:00:00] [###############################################################################################################################################] 1/1 txes (0.0s)##
Waiting for receipts.
⠉ [00:00:25] [###########################################################################################################################################] 1/1 receipts (0.0s)
##### 31
✅ [Success]Hash: 0x015de35ffae94f491d4630f2aec84c49ae8170d5ecf3f4c1cdc8718bc4a00052
Contract Address: 0x64B24E046259042e16a337Be4648CeAAF8Eb72C6
Block: 5071408
Gas Used: 106719
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Total Paid: 0. ETH (106719 gas * avg 0 gwei)
Transactions saved to: /hello_foundry/broadcast/Counter.s.sol/31/run-latest.json
Sensitive values saved to: /hello_foundry/cache/Counter.s.sol/31/run-latest.json
The broadcast directory will be updated automatically with the latest output of the deployment.
See the foundry deployment documentation.