This repository contains the implementations for Project Ganache
- Clone repo with
git clone this_repo_url
cd
into repo and install dependencies withyarn install
- Run tests with
npx hardhat test
(orhh test
if you have hardhat shorthand installed)
- Install the "Solidity + Hardhat" Extension
Install Node.js: https://nodejs.org/en/
If you’re not sure whether you already have it, check for its version in terminal by running:
node -v
(recommended to update to 16.15.1 LTS)
- Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
- Install node
nvm install --lts
- Install yarn
corepack enable
Upon installation, you should be able to run yarn install
to pull all the dependencies of the project.
Standard best practice is to store sensitive in a separate .env
file. This file should never leave your local machine, and is ignored when git push
-ing to remote repositories. To do this, make a blank .env
file in the root directory of the project, see the .env.example
. The following steps outline which keys we need for this repo.
-
Private Key:
Open Metamask and click the 3 dotted icon in the top right > Account details > Export private key > copy the key. Save the key in your .env file in the following format:
PRIVATE_KEY=“YourKeyHere”
(recommended to keep quotes)Remember that leaking this private key to anyone else WILL result in the loss of ALL funds from this address. It is highly recommended to create a new account used only for testing
-
Alchemy Keys:
Make an account with Alchemy: https://www.alchemy.com/
Signup with your Improbable Google account and choose
Ethereum + L2
when prompted for which ecosystem. Once in your dashboard, click+ Create App
button somewhere in top right of window and chooseEthereum
for chain, andEthereum Mainnet
for network. Repeat forGoerli
, giving you 2 apps in your dashboard. Two new entries should pop up under your Apps and copy just the Api Key (without the ‘https://…v2/' base URL). Save this in the.env
file like so:ALCHEMY_MAINNET_KEY="YourKeyHere"
ALCHEMY_GOERLI_KEY="YourKeyHere"
Finally, get some test Ether for Goerli from here: https://goerlifaucet.com/. (you will need to sign in with your Alchemy account)
Go back to your Terminal and stay in the root directory of the project for the following commands:
yarn test
runs the unit tests on your local machine on a fork of ethereum mainnet. This combines hh updateBlockNumber
, hh compile
, and hh test
sequentially, where each individual command can be run individually:
hh updateBlockNumber
is a small custom HardHat Task which fetches the latest Ethereum block if the one stored in the config file is more than 3 days old. We use this to pin to a specific block when forking mainnet to our local machine during testing
hh compile
compiles the smart contracts and generates typescript types. This needs to be run before hh test
separately the first time as the ./types
folder is part of ./.gitignore
, but is used by ./hardhat.config.ts
hh test
runs the unit tests found in the ./test
folder. See HardHat help pages for optional arguments & flags
[Update this section with appropriate commands when staging tests are written]
We make use of 3 static analysis tools to scan for common security vulnerabilities in smart contracts. The following setup instructions are for OS X (tested on M1 Max chip unless otherwise stated).
The static analysis tools have a few common prerequisites. These are:
- homebrew, a package manager for OS X. Installation instructions can be found here: https://brew.sh/
Homebrew can now be used to install the various packages used by the static analysis tools:
- Python3.8. You can check your current version with
python3 --version
in your terminal. If you didn't have homebrew installed before, then your python3 is the one distributed with OS X. This project makes use of homebrew, so we also use homebrew's python3 for consistency: - Install python3 with homebrew:
brew install python3
- Update symlinks with
brew link python3
. This will set the defaultpython3
on your machine to be the homebrew one. - Steps 3 and 4 will likely install a newer version of python3. To install python3.8, run
brew install [email protected]
- Make a note of where this python version is installed. Following this setup will likely place it in
/opt/homebrew/opt/[email protected]/bin
. We will need this location later.
Install the required packages:
brew tap ethereum/ethereum
brew install leveldb
brew install solidity
The static analysis tools recommend that each is installed in a separate virtual environment. This is to prevent incompatibility issues arising from the use of different versions of the same package by different tools. Install virtualenv
with:
pip3 install virtualenv
Each of the 3 static analysis tools will live in a different virtual environment. Typically all 3 environements can be inside the project's root directory. However, since these tools will be used in other smart contract projects, we can place them anywhere convenient outside of this project. Once you've decided your tools directory, cd
into it and create 3 virtual environments:
python3 -m venv env-slither
python3 -m venv env-mythril
virtualenv -p=/opt/homebrew/opt/[email protected]/bin/python3 env-manticore
Note that we are using the location from step 6 aboven (with/python3
added to the end of the path)
We're now ready to install the static analysis tools
- From inside the directory where the virtual environments were made, activate the environment with:
source env-slither/bin/activate
- Install with
pip3 install slither-analyzer
Change to the root directory of this hardhat project and run:
slither .
This will check all contracts in the ./contracts
directory against slither's database of vulnerabilities. More usage info can be found at: https://github.com/crytic/slither
- If you're in a virtual environment already that is not mythril's, leave with
deactivate
- As before, from inside the directory where the virtual environments were made, activate the environment with:
source env-mythril/bin/activate
- Install with
pip3 install mythril
If this doesn't work, try installing the nightly build of Rust with:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Reload the terminal and run the following:
rustup default nightly
Now repeat step 3
Change to the root directory of this hardhat project and run:
myth analyze contracts/**/*.sol --solc-json helpers/static-analysis-remappings.json
This will check all contracts for vulnerabilities in mythril's database. However, it's likely that this will not finish running for some time (~10 minutes). The reason for this is mythril uses symbolic execution, meaning that it tries to reach different contract states by varying the inputs to function call. Varying one input while keeping others constant can lead to different contract states, which is the equivalent of a different 'path' in the analysis. This branching behaviour can lead to many branches, and coupled with large recursion depths (default is a max recursion depth of 128), this will extend analysis times. We can visualise the branches by adding the --graph
flag, though this requires single contracts to be analysed at a time:
myth analyze contracts/MockReceiverSpender.sol --solc-json helpers/static-analysis-remappings.json --graph graphOut.html
(This takes 15 minutes to run on an Apple M1 Max)
In this case, any warnings can be ignored for MockReceiverSpender.sol as this is only used as a target during testing and not part of any production code.
Some helpful flags for myth
are:
--max-depth
, accepts auint
argument. Default = 128--execution-timeout
, accepts auint
argument (units in seconds). Default = 86400
More usage info can be found at: https://github.com/ConsenSys/mythril
Also see definition of create_analyzer_parser()
at https://mythril-classic.readthedocs.io/en/master/_modules/mythril/interfaces/cli.html for additional option flags
Manticore is only supported on Linux. The following was tested on Ubuntu 20.04 (using Windows Subsystem for Linux, laptop 11th gen i9 cpu)
- If you're in a virtual environment already that is not mythril's, leave with
deactivate
- As before, from inside the directory where the virtual environments were made, activate the environment with:
source env-manticore/bin/activate
- Install with
pip3 install "manticore[native]"
Some additional steps are required to use the correct version of protobuf (or the incorrect type formats will be generated). First try downgrading protobuf to the version manticore wants with:
pip3 install protobuf==3.20.*
If this does not work, use the default protocol buffer implementation (though as the error message would suggest, this can degrade performance as its using pure python parsing):
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
Like mythril, manticore also uses symbolic execution, so expect extended execution times. Analyze a contract by changing to the root directory of this hardhat project and run:
manticore contracts/ContractName.sol --solc-remaps @=node_modules/@ --contract ContractName
A couple of notes to keep in mind with the above command:
- The remappings do not take a json file as an argument like mythril, and the remappings need to be directly passed to the --solc-remaps flag as an argument
- Manticore also requires specifying which contract to analyse (as there are several contracts in a single file due to the imports). This will usually be the lowest level contract in the inheritance tree
More usage info can be found at: https://github.com/trailofbits/manticore
The above 3 tools will run automatically on every pull request to main
. Unlike the unit tests, these github action workflows are not a requirement for merging. It is up to the contributor opening the PR to check if these tools have run successfully, and whether any changes need to be made. This needs to be checked manually even if the runs show a green tick. This is because any issues found by the tools do not throw an error, and only print to the std.out. Issues can be checked with the following:
In the details page of the slither github action run, check the Run crytic/[email protected]
section. Check the final line of the output for:
. analyzed (X contracts with 59 detectors), 0 result(s) found
, where X = the number of contracts checked
In the details page of the mythril github action run, check the Run mythril analysis
section. Check that the output shows:
The analysis was completed successfully. No issues were detected.
In the details page of the mythril github action run, check the Run manticore analysis
section. Check that the output only shows INFO
-severity logs.
For setup instructions, please see the wiki link below.
yarn lint
will highlight all rule violations for both typescript and solidity, but not automatically fix any issues.
The eslint
package supports comprehensive auto-fixes, but ethlint does not. As such, the following workflow is recommended:
- Right-click anywhere in a solidity file and click
Format Document
. This will useprettier
to apply most of theethlint
rules (but violate some) - Run
yarn lint:fix
in terminal to apply all typescript and solidity fixes (wherever it can) - Proceed to manually fix ethlint’s rules, as well as moving input arguments to functions back to a single line. The latter is the only formatting choice the team currently prescribes which does not have a built-in rule checker in any formatting/linting tool.
Tasks are used to automate some actions, such as interacting with contracts. You can find all custom tasks in the tasks
folder.
If you want to add new tasks and create a separate file for this, import it into the tasks/index.ts
file.
To view all the tasks available in the project, use yarn hardhat
.
To find out details about running a specific task, use yarn hardhat help <TASK>
.
To run a task, use yarn hardhat [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]
.
If you want to run a task on a local node, use yarn hardhat --network localhost [OTHER GLOBAL OPTIONS] <TASK> [TASK OPTIONS]
If you want to run tasks for smart contracts other than the ones in your deployments
folder, add the corresponding variables to your .env
file (see the variables to run tasks
section in .env.example
).