How to install Foundry to debug smart contracts (Part 1)

bugbountydegen
8 min readSep 2, 2023

--

Learn how to deploy and debug easily any smart contract on the Ethereum blockchain.

Paradigm foundry-rs

As they say,

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.

https://github.com/foundry-rs/foundry

Apart of the speed another difference with Truffle or Hardhat is that the scripts and tests in Foundry are written in Solidity, not Javascript.

How to install foundry

Let’s have a quick look how to install it in our Linux system and get to understand how to run all the tooling:

$ curl -L https://foundry.paradigm.xyz | bash 
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 1765 100 1765 0 0 4412 0 --:--:-- --:--:-- --:--:-- 4412
Installing foundryup...
######################################################################## 100.0%
Detected your preferred shell is bash and added foundryup to PATH. Run 'source /home/degen/.bashrc' or start a new terminal session to use foundryup.
Then, simply run 'foundryup' to install Foundry.
$ . .bashrc
$ foundryup 
foundryup: installing foundry (version nightly, tag nightly-1c415857dd7b617190834dbcb361506f6143fed4)
foundryup: downloading latest forge, cast and anvil
################################################################################################################################################# 100.0%
foundryup: downloading manpages
################################################################################################################################################# 100.0%
foundryup: installed - forge 0.2.0 (1c41585 2022-09-04T00:08:27.451724173Z)
foundryup: installed - cast 0.2.0 (1c41585 2022-09-04T00:08:27.451724173Z)
foundryup: installed - anvil 0.1.0 (1c41585 2022-09-04T00:08:27.527236025Z)
foundryup: done

With that, we have finished our install of Foundry.

Let’s dive into the commands we got: forge, cast, anvil and chisel.

To sum up before entering the details:

  • forge: To build, compile, debug, deploy your smart contracts
  • cast: To interact with the blockchain via RPC calls
  • anvil: Your local Ethereum node
  • chisel: Solidity CLI shell for debugging

For a more extended parameter list and usage, let’s go one by one.

Forge is the Ethereum development and testing framework (Like hardhat or truffle):

$ forgeforge 0.2.0 (1c41585 2022-09-04T00:08:27.451724173Z)
Build, test, fuzz, debug and deploy Solidity contracts.
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
bind Generate Rust bindings for smart contracts.
build Build the project's smart contracts. [aliases: b]
cache Manage the Foundry cache.
clean Remove the build artifacts and cache directories. [aliases: cl]
completions Generate shell completions script. [aliases: com]
config Display the current config. [aliases: co]
coverage Generate coverage reports.
create Deploy a smart contract. [aliases: c]
debug Debugs a single smart contract as a script. [aliases: d]
flatten Flatten a source file and all of its imports into one file. [aliases: f]
fmt Formats Solidity source files.
geiger Detects usage of unsafe cheat codes in a foundry project and its dependencies.
generate-fig-spec Generate Fig autocompletion spec. [aliases: fig]
help Print this message or the help of the given subcommand(s)
init Create a new Forge project.
inspect Get specialized information about a smart contract. [aliases: in]
install Install one or multiple dependencies. [aliases: i]
remappings Get the automatically inferred remappings for the project. [aliases: re]
remove Remove one or multiple dependencies. [aliases: rm]
script Run a smart contract as a script, building transactions that can be sent onchain.
snapshot Create a snapshot of each test's gas usage. [aliases: s]
test Run the project's tests. [aliases: t]
tree Display a tree visualization of the project's dependency graph. [aliases: tr]
update Update one or multiple dependencies. [aliases: u]
upload-selectors Uploads abi of given contract to https://sig.eth.samczsun.com function selector database. [aliases: up]
verify-check Check verification status on Etherscan. [aliases: vc]
verify-contract Verify smart contracts on Etherscan. [aliases: v]
Find more information in the book: http://book.getfoundry.sh/reference/forge/forge.html

Cast is the CLI to interact with smart contracts on a low-level basis:

$ castcast 0.2.0 (1c41585 2022-09-04T00:08:27.451724173Z)
Perform Ethereum RPC calls from the comfort of your command line.
USAGE:
cast <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
--abi-decode Decode ABI-encoded input or output data [aliases: ad]
--address-zero Get zero address [aliases: address-zero, az]
--calldata-decode Decode ABI-encoded input data. [aliases: cdd]
--concat-hex Concatenate hex strings. [aliases: concat-hex, ch]
--format-bytes32-string Formats a string into bytes32 encoding.
--from-bin Convert binary data into hex data. [aliases: from-bin, fb]
--from-fix Convert a fixed point number into an integer. [aliases: from-fix, ff]
--from-rlp Decodes RLP encoded data. Input must be hexadecimal.
--from-utf8 Convert UTF8 text to hex. [aliases: from-utf8, --from-ascii, from-ascii, fu, fa]
--from-wei Convert wei into an ETH amount. Consider using --to-unit. [aliases: from-wei, fw]
--hash-zero Get zero hash [aliases: hash-zero, hz]
--max-int Get the maximum i256 value. [aliases: max-int, maxi]
--max-uint Get the maximum u256 value. [aliases: max-uint, maxu]
--min-int Get the minimum i256 value. [aliases: min-int, mini]
--parse-bytes32-string Parses a string from bytes32 encoding.
--to-ascii Convert hex data to an ASCII string. [aliases: to-ascii, tas, 2as]
--to-bytes32 Right-pads hex data to 32 bytes. [aliases: to-bytes32, tb, 2b]
--to-checksum-address Convert an address to a checksummed format (EIP-55). [aliases: to-checksum-address, --to-checksum, to-checksum, ta,
2a]
--to-dec Convert hex value into a decimal number. [aliases: to-dec, td, 2d]
--to-fix Convert an integer into a fixed point number. [aliases: to-fix, tf, 2f]
--to-hex Convert an integer to hex. [aliases: to-hex, th, 2h]
--to-hexdata Normalize the input to lowercase, 0x-prefixed hex. See --help for more info. [aliases: to-hexdata, thd, 2hd]
--to-int256 Convert a number to a hex-encoded int256. [aliases: to-int256, ti, 2i]
--to-rlp RLP encodes hex data, or an array of hex data
--to-uint256 Convert a number to a hex-encoded uint256. [aliases: to-uint256, tu, 2u]
--to-unit Convert an ETH amount into another unit (ether, gwei or wei). [aliases: to-unit, tun, 2un]
--to-wei Convert an ETH amount to wei. Consider using --to-unit. [aliases: to-wei, tw, 2w]
4byte Get the function signatures for the given selector from https://sig.eth.samczsun.com. [aliases: 4, 4b]
4byte-decode Decode ABI-encoded calldata using https://sig.eth.samczsun.com. [aliases: 4d, 4bd]
4byte-event Get the event signature for a given topic 0 from https://sig.eth.samczsun.com. [aliases: 4e, 4be]
abi-encode ABI encode the given function argument, excluding the selector. [aliases: ae]
access-list Create an access list for a transaction. [aliases: ac, acl]
age Get the timestamp of a block. [aliases: a]
balance Get the balance of an account in wei. [aliases: b]
basefee Get the basefee of a block. [aliases: ba, fee]
block Get information about a block. [aliases: bl]
block-number Get the latest block number. [aliases: bn]
call Perform a call on an account without publishing a transaction. [aliases: c]
calldata ABI-encode a function with arguments. [aliases: cd]
chain Get the symbolic name of the current chain. [aliases: ch]
chain-id Get the Ethereum chain ID. [aliases: ci, cid]
client Get the current client version. [aliases: cl]
code Get the bytecode of a contract. [aliases: co]
completions Generate shell completions script [aliases: com]
compute-address Compute the contract address from a given nonce and deployer address. [aliases: ca]
estimate Estimate the gas cost of a transaction. [aliases: e]
etherscan-source Get the source code of a contract from Etherscan. [aliases: et, src]
find-block Get the block number closest to the provided timestamp. [aliases: f]
gas-price Get the current gas price. [aliases: g]
generate-fig-spec Generate Fig autocompletion spec. [aliases: fig]
help Print this message or the help of the given subcommand(s)
index Compute the storage slot for an entry in a mapping. [aliases: in]
interface Generate a Solidity interface from a given ABI. [aliases: i]
keccak Hash arbitrary data using keccak-256. [aliases: k]
lookup-address Perform an ENS reverse lookup. [aliases: l]
namehash Calculate the ENS namehash of a name. [aliases: na, nh]
nonce Get the nonce for an account. [aliases: n]
pretty-calldata Pretty print calldata. [aliases: pc]
proof Generate a storage proof for a given storage slot. [aliases: pr]
publish Publish a raw transaction to the network. [aliases: p]
receipt Get the transaction receipt for a transaction. [aliases: re]
resolve-name Perform an ENS lookup. [aliases: rn]
rpc Perform a raw JSON-RPC request [aliases: rp]
run Runs a published transaction in a local environment and prints the trace. [aliases: r]
send Sign and publish a transaction. [aliases: s]
shl Perform a left shifting operation
shr Perform a right shifting operation
sig Get the selector for a function. [aliases: si]
storage Get the raw value of a contract's storage slot. [aliases: st]
tx Get information about a transaction. [aliases: t]
upload-signature Upload the given signatures to https://sig.eth.samczsun.com. [aliases: ups]
wallet Wallet management utilities. [aliases: w]
Find more information in the book: http://book.getfoundry.sh/reference/cast/cast.html

Next one, anvil is the local Ethereum node (Like Ganache or Hardhat node):

$ anvil
_ _
(_) | |
__ _ _ __ __ __ _ | |
/ _` | | '_ \ \ \ / / | | | |
| (_| | | | | | \ V / | | | |
\__,_| |_| |_| \_/ |_| |_|
0.1.0 (1c41585 2022-09-04T00:08:27.527236025Z)
https://github.com/foundry-rs/foundry
Available Accounts
==================
(0) 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
(1) 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 (10000 ETH)
(2) 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc (10000 ETH)
(3) 0x90f79bf6eb2c4f870365e785982e1f101e93b906 (10000 ETH)
(4) 0x15d34aaf54267db7d7c367839aaf71a00a2c6a65 (10000 ETH)
(5) 0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc (10000 ETH)
(6) 0x976ea74026e726554db657fa54763abd0c3a0aa9 (10000 ETH)
(7) 0x14dc79964da2c08b23698b3d3cc7ca32193d9955 (10000 ETH)
(8) 0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f (10000 ETH)
(9) 0xa0ee7a142d267c1f36714e4a8f75612f20a79720 (10000 ETH)
Private Keys
==================
(0) 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
(1) 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
(2) 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
(3) 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
(4) 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
(5) 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
(6) 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e
(7) 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356
(8) 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97
(9) 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
Wallet
==================
Mnemonic: test test test test test test test test test test test junk
Derivation path: m/44'/60'/0'/0/
Base Fee
==================
1000000000Gas Limit
==================
30000000Genesis Timestamp
==================
1662332232Listening on 127.0.0.1:8545

And finally chisel, that allow us to do extended debugging and run Solidity code directly from a shell:

$ chiselWelcome to Chisel! Type `!help` to show available commands.
➜ !help
⚒️ Chisel help
=============
General
!help | !h - Display all commands
!quit | !q - Quit Chisel
!exec <command> [args] | !e <command> [args] - Execute a shell command and print the output

Session
!clear | !c - Clear current session source
!source | !so - Display the source code of the current session
!save [id] | !s [id] - Save the current session to cache
!load <id> | !l <id> - Load a previous session ID from cache
!list | !ls - List all cached sessions
!clearcache | !cc - Clear the chisel cache of all stored sessions
!export | !ex - Export the current session source to a script file
!fetch <addr> <name> | !fe <addr> <name> - Fetch the interface of a verified contract on Etherscan
!edit - Open the current session in an editor
Environment
!fork <url> | !f <url> - Fork an RPC for the current session. Supply 0 arguments to return to a local network
!traces | !t - Enable / disable traces for the current session
!calldata [data] | !cd [data] - Set calldata (`msg.data`) for the current session (appended after function selector). Clears it if no argument provided.
Debug
!memdump | !md - Dump the raw memory of the current state
!stackdump | !sd - Dump the raw stack of the current state
!rawstack <var> | !rs <var> - Display the raw value of a variable's stack allocation. For variables that are > 32 bytes in length, this will display their memory pointer.

That’s it for the first part of the series, in the following post we will learn how to deploy and debug smart contracts using Foundry.

More info:

GitHub foundry-rs

Paradigm Georgios Konstantopoulos

Follow me on Twitter: @bugbountydegen

Give a try to my 💰 Smart Contract Security Analysis Platform: SmartAuditor.AI! On-chain scans and security patterns search.

--

--