I couldn’t find a complete project setup guide with forge that satisfied my use-case so I made one. And by complete I mean one that does:
- Build, test, debug
- Deployment
- Verification
Here’s an opinionated guide on how to setup forge, its roughly the same as the github readme and exists here solely as an SEO funnel.
Overview
Uses vscode + eslint plugin + solidity plugin.
- remappings.txt for vscode solidity linter
- foundry.toml to config forge
- Uses forge to compile, test, and debug.
- Uses a custom JS script to deploy, see deploy.js.
I prefer to write the deployment scripts as programatically as possible on a widely supported language as every deployment itself is unique, and sometimes there’s inter-dependencies between contracts.
For example:
- Deploy contract A
- Deploy contract B
- Call addOwner on B with A’s address
This is overly tricky with bash for me, and would require a LOT of unreadable (and error-prone) commands-line composition with jq and awk to achieve that with the default forge create
.
Development
Building and testing
forge build
forge test
# forking from existing state
# -vvv = very very verbose
forge test -f http://127.0.0.1:8545 -vvv
# To access the debugger
forge run --debug src/test/Contract.t.sol --sig "testExample()"
Contract Deployment
Copy .env.example
to .env
and fill it out with correct details.
node --experimental-json-modules scripts/deploy.js
Etherscan Verification
Forge has a very useful in-built etherscan verification utility.
# For list of compiler versions https://etherscan.io/solcversions
forge verify-contract --compiler-version v0.8.12+commit.f00d7308 [CONTRACT ADDRESS] --constructor-args <ARGS> --num-of-optimizations 200 [CONTRACT_PATH:CONTRACT_NAME] [ETHERSCAN_API_KEY]
# To check verification status
forge verify-check [GUID] [ETHERSCAN_KEY]
If you have multiple contracts with pragma abiencoderv2
, there is a possibility that you can’t verify your contracts on etherscan, there’s an open issue on this.
One way to get around it is via paulrberg’s multisol or hjubb’s solt and verify it manually via the official interface.
The caveat to the approach above is that you have to have to copy the libraries in lib
to node_modules
and make sure the path matches as it doesn’t read remappings.
For example:
cp -r lib/openzeppelin-contracts node_modules/@openzeppelin
mv node_modules/@openzeppelin/contracts/* node_modules/@openzeppelin
multisol src/Contract.sol