Brownie framework for Smart Contracts

This post will serve as a reference on how to use Brownie development framework when dealing with EVM compatible blockchains like Ethereum or Binance Smart Chain. I did choose this framework since it’s based in python programming language which is easier IMHO than JavaScript one and I am interested only in auditing the smart contracts for security vulnerabilities and no client side interaction is needed.

for demonstration purpose I will use ethernaut CTF which is a fantastic project done by OpenZeppelin to study common security vulnerabilities that lies on EVM compatible smart contracts.

Installation

pipx python tool can be used to install the Brownie quickly as stated in the official documentations

# pipx install eth-brownie

Usage

Now before start using the Brownie tool you should have a running blockchains, this can be a real network like Ethereum main network or a test network like a local instance running in your machine. For testing purpose I do use the Ganache tool ganache from Truffle Suite, Ganache will Quickly fire up a personal Ethereum blockchain which you can use to run tests, execute commands, and inspect state while controlling how the chain operates. please refer to the tool documentations on how to install it, However if you are using a Linux box then just download the AppImage file, run it from the command line and leave it in the background

# ./ganache.AppImage &  

Brownie works like a command interpreter so you have to pass to it options to carry on different tasks. for start we will pass init command which will populate different directories and files for our ethernaut project.

# brownie init

In the above screenshot you will notice that Brownie did create various directories/files, in nutshell the contracts folder host your smart contracts source code files, build folder have contracts folder which will come handy since it’s hosting the ABI interface that tell us how to interact with the deployed smart contracts i.e. what is the parameters name and type.

the .env file is the environment file for the current project, I do use it to specify the API key when connecting to public Ethereum networks using the Infura nodes. the brownie-config.yaml is where the configurations for the current project is saved, for example We can specify what’s the default network connection or default compiler version.

Now let’s create a file named fallback.sol inside the contracts folder which is the first level of the ethernaut CTF. VSCode is my go-to IDE when comes to code writing.

you will notice in the code that I did import the SafeMath.sol locally since I have a copy of it inside the project folder, I prefer to have a local copy to read the code behind and test different scenarios.

Next We are ready to fire up the Brownie and start interacting with the smart contact, please remember that Ganache must be running before starting the Brownie console

# brownie console

Brownie will compile all contracts in the project when starting and fail if there is any compilation errors, the great thing about Brownie is that it will automatically download the proper solidity compiler according the version specified in the source code.

Now we can deploy the contract and create an instance of it on the Ganache testing blockchain using the following command where I did specify the first account in the blockchain as the deployer, the fallback smart contract will use this info to set the first account as the owner of the deployed contract and brownie will give us back a python object that will be used to interact with the contract:

# Fallback.deploy({'from':accounts[0]})

Brownie can help us when querying the blockchain about smart contract different information, for example We can ask the blockchain who is the owner of the contract and what is the balance of Ethers inside the contract and many other great commands that help us when working with contracts

# Fallback[0].owner.call()  // who is the owner ?
# Fallback[0].balance() // what is the balance of this contract ?
# network.show_active() // what is our current connected blockchain ?
# dir(accounts[0]) // show the methods/properties of the account object
# web3.fromWei(97994022120000000000,'ether') // convert wei value to Ether

We can transfer Ethers easily between accounts or contracts using the following transfer command

# accounts[1].transfer(Fallback[0].address, 20000)

also can interact with functions inside the smart contract, for example the contribute or withdraw methods

# Fallback[0].contribute({'from':accounts[1], 'value':'20000'})
# Fallback[0].withdraw({'from':accounts[1]}) 

Please keep in mind that the above commands do not solve the fallback challenge 😉 it’s just for illustrations purpose. In case We want to have a fresh instance of the smart contract We can deploy another one easily again using the prior deploy command and the new python object will be called Fallback[1].

References:

https://eth-brownie.readthedocs.io/en/stable/

https://www.trufflesuite.com/ganache

https://docs.soliditylang.org