Subscribe to our free newsletter

To make sure you won't miss any valuable content we share with our community.

Using Ganache CLI with Brownie to Deploy A Smart Contract

In this article, after installing Brownie, we are going to install the Ganache CLI (Command Line Interface) and use it with Brownie. The Ganache CLI is the same as Ganache IDE with the difference that it automatically runs without the need to open the Ganache IDE. At the end end of this tutorial, we will be able to deploy our smart contracts on top of Ganache CLI simulated blockchain.

Installing Ganache:

To continue our journey with Brownie, we need to make sure Ganache CLI has been installed successfully. To make sure that it has, and also see its virtual accounts, in your console (terminal) write:

ganache

And it should give you the test accounts like this:


ganache v7.0.3 (@ganache/cli: 0.1.4, @ganache/core: 0.1.4)
Starting RPC server

Available Accounts
==================
(0) 0x960F41C52ffAef71fFef2fFBC3C0EA5Dc5748086 (1000 ETH)
(1) 0x39Cf64532C1126c6C9Fa0a02338389d1eb861A12 (1000 ETH)
(2) 0xA1E47c46425e24565666ED350e1edEf6532f348c (1000 ETH)
(3) 0xE441bb58b5369DB428a979fbE77Df2d3Da1F91d4 (1000 ETH)
(4) 0x4498662A9691cfef775d3D212f5938905B5de70E (1000 ETH)
(5) 0x4Da709036c65CB81bF74970945f21Ac2e42e9cA9 (1000 ETH)
(6) 0x32872e4dDB4c4876e7B1359013696344fd976C22 (1000 ETH)
(7) 0x6aadaB117c9f26726D5e23b9A0fdC475F3BEd181 (1000 ETH)
(8) 0xCf763def60f3247CE5bEF18BAfC080dA3573595b (1000 ETH)
(9) 0x3a6AFe48C0889820aa587E9Dd45D1B7d8E4e5039 (1000 ETH)

Private Keys
==================
(0) 0x1093c2edf08326559ffbaccfe2a5c5826d2bee9b42fc71c51ad8d989100a3a31
(1) 0x4ebeaf4a4bb07a875255d1f4627146dcc69c930cc380701e1f338d1975240135
(2) 0xa25ad60447f26ad265962660c88bb04ff671f3a55c0f59985530088dad82c9c8
(3) 0x706fce79c758f53fc9336507a35d66ec285c8f52147a6f7676a0e89925f21d0c
(4) 0xd92dc461456414fa41af48ca8806a50031bdc4d587b8e49b1a3f501790f4b853
(5) 0x0b467e91bb9fef30c51077d9a7ba4b9d0797fe46f7fc1cff202751d9bfcf0bb0
(6) 0xaa05bda4d14e2fd3cac04174feeca371567b8f990acc6fab001f0b3317680d50
(7) 0x3a263493e9763bb5b7f069cd51cbca836298831d59b7f57125c937f8ef76dd82
(8) 0x4d6edbb1e7d4283cdf7cc8ce802ef72bcb7b684a51ab7098834e48a638bcfae5
(9) 0x5cb8a425439d9db86c6a58438fb5a6fa425ab60c675d9fd90bdc14cf093bf33c

HD Wallet
==================
Mnemonic:      patrol juice song save pretty combine dish table sock robust glow bunker
Base HD Path:  m/44'/60'/0'/0/{account_index}

Default Gas Price
==================
2000000000

BlockGas Limit
==================
30000000

Call Gas Limit
==================
50000000

Chain Id
==================
1337

RPC Listening on 127.0.0.1:8545


If you don’t get the above results or you get:

ganache is not recognized …

You might need to install it and that shows that Ganache CLI has not yet been installed. Notice that on Linux, instead of writing:

npm install –-global ganache

You should add sudo at the beginning of the command. Otherwise, it will throw an error saying that the node modules folder is not in usr/local/lib directory. So for Linux, we install the Ganache CLI like this:

sudo npm install –global ganache

Also, before installing the Ganache CLI, you need to make sure you have the node installed on your OS. You can check it by typing:

node -v

Result:

v16.14.2

Deploying the Contract Using Ganache CLI:

After that, we make sure that all the dependencies have been installed, we can continue with Brownie scripts on deploy.py:
First, run Brownie:

brownie

Then, fetch one of the Ganache accounts using the following code in the deploy.py file:


from brownie import accounts

def deploy_simple_storage():
	account = accounts[0]
	print(account)

def main():
	deploy_simple_storage()


We will run the project by the following command in the terminal (In the directory of the project’s folder):

brownie run scripts/deploy.py

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieSimpleStorageProject is the active project. Attached to local RPC client listening at '127.0.0.1:8545'... Running 'scripts/deploy.py::main'... 0x960F41C52ffAef71fFef2fFBC3C0EA5Dc5748086

Using Environment Variables for the Private Key:

If you can remember from the previous tutorial, we added the Metamask account to Brownie and the terminal asked for the private key. Now, if we do not want to enter the password every time and make the process run automatically without asking the user for a private key or password, we go after the environment variables again. But, this time is a little a bit different. Like before, we create a .env file and paste our private key:


export PRIVATE_KEY= “here goes your private key”

Then, we create a file called brownie-config.yaml and paste the following code:


dotenv: .env
wallets:
	from_key: ${PRIVATE_KEY}


Then, we modify our deploy.py file as below:


from brownie import accounts, config

def deploy_simple_storage():
	account = accounts.add(config["wallets"]["from_key"])
	print(account)

def main():
	deploy_simple_storage()



And if we run it by the following command in the terminal:

brownie run scripts/deploy.py

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieSimpleStorageProject is the active project. Attached to local RPC client listening at '127.0.0.1:8545'... Running 'scripts/deploy.py::main'... 0x25E681EE76469E4cF846567b772e94e082907117

Now to actually deploy the simple storage contract, we import the SimpleStorage in the deploy.py file and also add the contract.deploy({}) line to the first function:


def deploy_simple_storage():


from brownie import accounts, config, SimpleStorage

def deploy_simple_storage():
	account = accounts.add(config["wallets"]["from_key"])
	SimpleStorage.deploy({"from": account})

def main():
	deploy_simple_storage()


And

brownie run scripts/deploy.py

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieSimpleStorageProject is the active project. Launching 'ganache-cli --chain.vmErrorsOnRPCResponse true --server.port 8545 --miner.blockGasLimit 12000000 --wallet.totalAccounts 10 --hardfork istanbul --wallet.mnemonic brownie'... Running 'scripts/deploy.py::main'... Transaction sent: 0x1d70d1a30b0266da050d696c14b749bb5e34425159817e5f6e66b1e615221685 Gas price: 0.0 gwei Gas limit: 12000000 Nonce: 0 SimpleStorage.constructor confirmed Block: 1 Gas used: 334180 (2.78%) SimpleStorage deployed at: 0x647Dc9EE9731d35b9031A9ca6c664D6b75d14385 Terminating local RPC client…

Deploying the Contract with the Ganache CLI Accounts

You can also test this with the Ganache accounts:


from brownie import accounts, config, SimpleStorage

def deploy_simple_storage():
	account = accounts[0]
	SimpleStorage.deploy({"from": account})

def main():
	deploy_simple_storage()


Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieSimpleStorageProject is the active project. Launching 'ganache-cli --chain.vmErrorsOnRPCResponse true --server.port 8545 --miner.blockGasLimit 12000000 --wallet.totalAccounts 10 --hardfork istanbul --wallet.mnemonic brownie'... Running 'scripts/deploy.py::main'... Transaction sent: 0xbbd21a1abc42f0d21f4651b71cddadddecf6ba99af3a31a140434950c7e36876 Gas price: 0.0 gwei Gas limit: 12000000 Nonce: 0 SimpleStorage.constructor confirmed Block: 1 Gas used: 334180 (2.78%) SimpleStorage deployed at: 0x3194cBDC3dbcd3E11a07892e7bA5c3394048Cc87 Terminating local RPC client…

Great! Now we have managed to deploy our contract using Brownie. The Brownie adventure however is goes on in our other articles.

Summing Up

In this article, we have managed to install the Ganache CLI, to be able to automatically use it whenever we want to test our deployment in a simulated blockchain. We have also considered a way to include our private key somewhere safe (in the .env file) out of the deploy.py script file. In the end, we deployed our contract using the Ganache CLI.

Download this Article in PDF format

3d websites

Care to Know Us More?

In Arashtad, we have gathered a professional team of developers who are working in fields such as 3D websites, 3D games, metaverses, and other types of WebGL and 3D applications.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Request a Quote
ThreeJS Development

How to Install and Use Brownie to Deploy A Smart Contract

In this article, we are going to install and use Brownie as a much simpler tool to deploy Solidity smart contracts using python scripts. Throughout this tutorial, we will install Brownie, create a Brownie project folder and deploy the simple storage smart contract. You will see that the whole process is done much easier and faster with Brownie rather than python web3.py scripts.

Install and Use Brownie to Deploy A Smart Contract

We have learned how to deploy our smart contracts using python web3 tools, but if you look at the scripts you will see that we have taken a very long way to get there. However, there is an easier and more efficient way to deploy our contracts in python and that is Brownie. Brownie is the most common smart contract development platform built based on python. It is used by DeFi giants like Curve DAO, Yearn Finance, and Badger DAO. Brownie relies on web3.py. That’s why we started our first python tutorials with web3.

Install Brownie

To install Brownie, we need to first install pipx. Pipx will automatically create a virtual environment and after install Brownie using it, makes it available on the terminal. To install pipx on your terminal, use:

python3 -m pip install --user pipx

And on Linux, you should also install the following:

apt install python3.8-venv

And then:

python3 -m pipx ensurepath

And now, we can install Brownie:

pipx install eth-brownie

And, upgrade it:

pipx upgrade eth-brownie

Creating a Brownie project:

If you want to make sure that Brownie has been successfully installed open another terminal and type: brownie –version

Now, that Brownie has been installed, let’s create our first project using it:

mkdir brownie_simple_storage

And then to create our files automatically:

brownie init

And you will be able to see that a number of files have been created afterward.

Build File:

Keeps track of low-level stuff like the .json file of the contract, deployments, and interfaces.

Contracts File:

Where we write our contract.

Interfaces File:

Where we store our interface tools to make it easier to work with the blockchain And other folders which we talk about later. So, inside our contracts folder, we make a file called SimpleStorage.sol:

cd contracts touch SimpleStorage.sol

And copy and paste the recent SimpleStorage contract that we wrote on Solidity tutorials.


// SPDX-License-Identifier: MIT

pragma solidity >= 0.6.0 < 0.9.0;

contract SimpleStorage {

    uint256 Salary;
    struct Employees {
	uint256 Salary;
	string name;
    }

    Employees[] public employee;
    mapping(string => uint256) public nameToSalary;

    function store(uint256 _Salary) public {
	Salary = _Salary;
    }

    function retrieve() public view returns (uint256){
	return Salary;
    }

    function addPerson(string memory _name, uint256 _Salary) public {
	employee.push(Employees(_Salary, _name));
	nameToSalary[_name] = _Salary;
    }
}


now if you go back to the main folder and type: brownie compile

You will see that the project has been easily compiled without the need of any scripts. And also if you go to build/contracts , you will be able to see the .json file with the name of the contract SimpleStorage.json. And if you can remember from the previous tutorials, the .json file of the contract contains data like ABI, bytecode, opcode, and so on.

Deploying the Contract Using Brownie

Now, it is time to deploy this contract using Brownie. So to do that we go to the scripts folder and create a file called deploy.py. And before we start writing our scripts, let’s review our python code on web3. We needed ABI and bytecode which Brownie has automatically provided out of our smart contract, we also needed RPC URI that we copied from either Ganache or Infura. The Brownie here uses Ganache-cli and you need to make sure you have it installed if you want to deploy your contracts. The following code should be written in deploy.py.


from brownie import accounts

def deploy_simple_storage():
    account = accounts[0]
    print (account)

def main():
    print("Hello World!")


And it is run by typing:

brownie run /scripts/deploy.py

In the terminal, we will see that we are given an account address with its private key.
There is also another way to have an account on Brownie and that is to use our Metamask wallet.
To do that, in the terminal we write:

brownie accounts new MyAccount

And you will see that the terminal asks you to enter your private key:

Now, you can copy and paste your account private key to introduce it to Brownie and be able to use it afterward. Then, you enter a password:

SUCCESS: A new account '0x25E681EE76469E4cF846567b772e94e082907117' has been generated with the id 'MyAccount'

You will see the above result on the terminal. And it tells you that you can use the ‘MyAccount’ id instead of writing your private key.
You can write in console:

brownie accounts list

Result:

Found 1 account: └─MyAccount: 0x25E681EE76469E4cF846567b772e94e082907117

And, if you want to retrieve your private key in the future, we write in our deploy.py:


from brownie import accounts

def deploy_simple_storage():
    account = accounts.load("MyAccount")
    print(account)

def main():
    print("Hello World!")


After running this code by writing:

brownie run /scripts/deploy.py

We will see that the terminal asks us about our password So that we can finally access our private key. Notice that this a safer way than using a .env file, but still using environment variables is a safe way to protect your private key.
We can also delete our account using this command:

brownie accounts delete MyAccount

Result:

SUCCESS: Account 'MyAccount' has been deleted

Last Thought

So, up to now, we have learned about some of the good features and capabilities of Brownie and we have managed to deploy our smart contract much easier than with python web3 tools, this time using Brownie. However, managing the installed Brownie to deploy a Simple Storage contract is the least we can do. So, We’re going to cover the next stages in our next articles.

Download this Article in PDF format

web developement

Check Out Our Services

In Arashtad, we’re working on 3D games, metaverses, and other types of WebGL and 3D applications with our 3D web development team. However, our services are not limited to these. Back-end developments, front-end developments, 3d modeling, and animations are in our arsenal too.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
Blockchain Development

Working with Crowdfunding on Etherscan Using Brownie and Solidity

In this tutorial, we are going to implement the crowdfunding project folder and compile it. Then we are going to interact with the compiled and deployed crowdfunding contract on the Etherscan. There are a number of scripts that we are going to work on. They are helpful_scripts.py, deploy.py, brownie_config.yaml, Fundme.sol, and .env file.

Crowdfunding on Etherscan: the Essentials

If you have read the solidity smart contracts tutorial, you can remember how we wrote the FundMe.sol contract and how we deployed it using Remix IDE. As you know, Remix IDE is just for learning solidity and beginners and we need some other deployment tools such as Node.js or Python web3, or brownie to be able to run it in a real-world application. To set up the Fundme.sol contract inside Brownie, we take the following steps:

1. Create a directory folder for the project:

mkdir brownie_fund_me

2. In the terminal:

brownie init

3. Inside the contracts folder, create a file called FundMe.sol and paste the FundMe smart contract that we wrote earlier in it.

Fundme.sol:


// SPDX-License-Identifier: MIT

pragma solidity >= 0.6.6 < 0.7.0;

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "@chainlink/contracts/src/v0.6/vendor/SafeMathChainlink.sol";

contract FundMe {
	using SafeMathChainlink for uint256;
	mapping(address => uint256) public addressToAmountFunded;
	address[] public funders;
	address public owner;

	constructor() public {
		owner = msg.sender;
	}

	function fund() public payable {
		uint256 minimumUSD = 50 * 10 ** 18;	
		require(getConversionRate(msg.value) >= minimumUSD, "You need to spend 	more ETH!");
		addressToAmountFunded[msg.sender] += msg.value;
		funders.push(msg.sender);
	}

	function getVersion() public view returns (uint256){
		AggregatorV3Interface priceFeed = 		
		AggregatorV3Interface(0x8A753747A1Fa494EC906cE90E9f37563A8AF630e);
		return priceFeed.version();
	}

	function getPrice() public view returns(uint256){
		AggregatorV3Interface priceFeed = AggregatorV3Interface
			(0x8A753747A1Fa494EC906cE90E9f37563A8AF630e);
		(,int256 answer,,,) = priceFeed.latestRoundData();
		return uint256(answer * 10000000000);
	}

	function getConversionRate(uint256 ethAmount) public view returns (uint256){
		uint256 ethPrice = getPrice();
		uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
		return ethAmountInUsd;
	}

	modifier onlyOwner {	
		require(msg.sender == owner);
		_;
	}

	function withdraw() payable onlyOwner public {
		msg.sender.transfer(address(this).balance);
		for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++){
			address funder = funders[funderIndex];
			addressToAmountFunded[funder] = 0;
		}
		funders = new address[](0);
	}
}


Deploy.py

4. In the scripts folder of the directory, create a deploy.py file with the following code , so that you can interact with the smart contract:


from brownie import FundMe
from scripts.helpful_scripts import get_account

def deploy_fund_me():
	account = get_account()
	fund_me = FundMe.deploy({"from":account})
	print(f"Contract deployed to {fund_me.address}")

def main():
	deploy_fund_me()


Helpful_scripts.py

5. Create another file named helpful_scripts.py and paste the below codes in it:

from brownie import network, config, accounts

def get_account():
	if network.show_active() == "development":
	return accounts[0]
else:
	return accounts.add(config["wallets"]["from_key"])


This piece of code helps deploy.py find the account it should connect to. In order to make it possible for deploy.py to import this file, you should create another file called __init__.py.

Brownie-config.yaml

6. In the main directory create a file named brownie-config.yaml and paste the below scripts in it.


dependencies:
# - @
	- smartcontractkit/[email protected]
compiler:
	solc:
		remappings:
			- '@chainlink=smartcontractkit/[email protected]'

dotenv: .env
wallets:
	from_key: ${PRIVATE_KEY}


We have defined the chainlink smart contract kit as a dependency to be able to use it afterwards. We have also defined using environment variables and reading from the private key.

.env file

7. Create a .env file and paste your private key and Infura Rinkeby id inside of it.


export PRIVATE_KEY=
export WEB3_INFURA_PROJECT_ID=


8. Now that all files are set up, in your terminal write:

brownie compile

Result:

Brownie v1.18.1 - Python development framework for Ethereum Downloading from https://solc-bin.ethereum.org/linux-amd64/solc-linux-amd64-v0.6.12+commit.27d51765 100%|█████████████████████████████████████████████████████████████████████████████████████| 9.47M/9.47M [00:46<00:00, 204kiB/s] solc 0.6.12 successfully installed at: /home/mohamad/.solcx/solc-v0.6.12 Compiling contracts... Solc version: 0.6.12 Optimizer: Enabled Runs: 200 EVM Version: Istanbul Generating build data... - smartcontractkit/[email protected]/AggregatorV3Interface - smartcontractkit/[email protected]/SafeMathChainlink - FundMe Project has been compiled. Build artifacts saved at /home/mohamad/brownie_fund_me/build/contracts

Deploying the Crowdfunding Smart Contract:

9. The final step is to deploy the smart contract:

brownie run scripts/deploy.py --network rinkeby

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieFundMeProject is the active project. Running 'scripts/deploy.py::main'... Transaction sent: 0xaffb135e4da5e5d52df7fb852194c47459f93614ad6dfdf098890c16c9138d58 Gas price: 1.000000019 gwei Gas limit: 396322 Nonce: 50 FundMe.constructor confirmed Block: 10428096 Gas used: 360293 (90.91%) FundMe deployed at: 0xD13F9dA0C0AFA03B5115F2007863Ab87404fDA5d Contract deployed to 0xD13F9dA0C0AFA03B5115F2007863Ab87404fDA5d

Now, we can go to Rinkeby Etherscan again and track our deployment. In the contract section, we will see:

crowdfunding on Etherscan

So far so good! But we have a problem here. We are not yet able to interact with the smart contract. To do this manually, you can click on verify and publish. On the new page, you enter the contract address, compiler type and its license and press continue.

crowdfunding on Etherscan

We can enter the solidity FundMe.sol contract code in the space given. Also do not forget to toggle optimization from no to yes.

crowdfunding on Etherscan

We can copy and paste our smart contract. But there is a problem, Etherscan will not be able to identify chainlink AggregatorV3Interface.sol. We have a solution for this in the next section of our tutorial.

Crowdfuning on Etherscan: Getting An API Key

In this section, we are going to get an API key from etherscan.io and paste it into the .env file to be able to keep track of our crowdfunding smart contract on the Rinkeby chain Etherscan. Also, we're going to interact with the fund me smart contract with a simple-to-use interface. As you recall, we had a problem and it was that we couldn’t paste our code inside the box related to smart contracts because Etherscan could not identify the chainlink Aggregator. But, there is a solution for that.
First, we should head over to etherscan.io and sign up for an account and then in the More tab Developers section click on API documentation:

crowdfunding on Etherscan

Then, on the left hand side bar, click on API keys:

crowdfunding on Etherscan

And add an API with the name verify_brownie:

crowdfunding on Etherscan

After adding an API key, copy it:

crowdfunding on Etherscan

And paste it into the .env file like this:


export ETHERSCAN_TOKEN=

Also, in the deploy.py file, change:


fund_me = FundMe.deploy({"from":account})

To


fund_me = FundMe.deploy({"from":account},publish_source=True)

To be able to publish our code on Rinkeby Etherscan.
Now, it is time to run our code once more:

brownie run scripts/deploy.py --network rinkeby

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieFundMeProject is the active project. Running 'scripts/deploy.py::main'... Transaction sent: 0xd0bced9c51f3c79e3bda4a150600159480c49ab8c7e7fb57b92112b3ee4efc80 Gas price: 1.000000013 gwei Gas limit: 396322 Nonce: 51 FundMe.constructor confirmed Block: 10428922 Gas used: 360293 (90.91%) FundMe deployed at: 0xC9bA69ceb32E132a6cf32138534EB32647D87d7a Waiting for https://api-rinkeby.etherscan.io/api to process contract... Verification submitted successfully. Waiting for result... Verification complete. Result: Pass - Verified Contract deployed to 0xC9bA69ceb32E132a6cf32138534EB32647D87d7a

Interacting on Rinkeby Etherscan:

Now, if we go to Rinkeby Etherscan and paste the address of the contract (given in the terminal) in the search bar, we will be able to see that the contract tab is checked:

smart contract

If you go to the contracts section, you will be able to see that the FundMe.sol is published with its chainlink dependency code. Also, ABI of the contract is published in another box.

smart contract

If we try posting the contract and press any of the keys related to public data, we will be able to retrieve them.

smart contract

Also, if we go to write the contract and click on connect to web3, we can connect our Metamask wallet to Etherscan and fund the project using the test ethers in the Rinkeby account.

smart contract

smart contract

You can enter 1 in the box under fund and press the Write button and confirm the Metamask pop-up:

smart contract

Once, the transaction has been confirmed, we can withdraw that 1 ether back into our account:

smart contract

By doing the exact same process for the Mainnet account, we will be able to write and deploy a real-world smart contract!

Conclusion

In this article, we have managed to create and organize the crowdfunding project folder and compile it. Then, we started the interaction with the compiled and deployed the crowdfunding contract using the Etherscan. There are a number of scripts that we have worked on such as helpful_scripts.py, deploy.py, and brownie_config.yaml, Fundme.sol and .env file.
Finally, we have managed to completely interact with the Fundme.sol smart contract using the address we have got in the terminal at the time we de-ployed the Fundme.sol contract. In this interaction which is on the Rinkeby chain (Ethereum test network), we can fund the contract and withdraw the funds as the admin.

Download this Article in PDF format

metaverse

Care to Know About Metaverse?

In Arashtad, we are providing custom services on 3d developments such as 3d websites, 3d models, metaverses and all 3d applications.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
Blockchain Development

Crowdfunding Smart Contract on Mainnet and Other Networks: A Perfect Tutorial

In this tutorial, we are going to write the complete scripts for the crowdfunding smart contract and organize the files related to the deployment of the smart contract in their own folders. We are also going to create a .env file to keep the private key and Infura project ID somewhere safe. In addition to that, the config file is going to help us categorize different networks with their account addresses.

Crowdfunding Smart Contract: Where to Start?

To start writing scripts for crowdfunding smart contracts, we are going to modify the code in a way that it will be possible to work with different networks such as Ganache CLI, development, Rinkeby, Mainnet, and so on. The folders and files remain the same and we only modify some of the scripts and add some other files to the project. Follow the steps and read the explanations to understand why we do what we do:

1. Inside the contracts folder, create another folder and name it test. And inside of it create a file called, MockV3Aggregator.sol then copy and paste this link URL into it:

The reason we do this, is to be able to use it when we are working with Ganache CLI and other networks as well.

2. We need to also modify FundMe.sol just a bit to be able to enter the eth_to_usd address for all the networks:


// SPDX-License-Identifier: MIT

pragma solidity ^ 0.6.6;

import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";
import "@chainlink/contracts/src/v0.6/vendor/SafeMathChainlink.sol";

contract FundMe {

	using SafeMathChainlink for uint256;
	mapping(address => uint256) public addressToAmountFunded;
	address[] public funders;
	address public owner;
	AggregatorV3Interface public priceFeed;

	constructor(address _priceFeed) public {
		priceFeed = AggregatorV3Interface(_priceFeed);
		owner = msg.sender;
	}

	function fund() public payable {
		uint256 minimumUSD = 50 * 10**18;
		require(getConversionRate(msg.value) >= minimumUSD,"You need to spend more ETH!");
		addressToAmountFunded[msg.sender] += msg.value;
		funders.push(msg.sender);
	}

	function getVersion() public view returns (uint256) {
		return priceFeed.version();
	}

	function getPrice() public view returns (uint256) {
		(, int256 answer, , , ) = priceFeed.latestRoundData();
		return uint256(answer * 10000000000);
	}


	function getConversionRate(uint256 ethAmount) public view returns (uint256) {
		uint256 ethPrice = getPrice();
		uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
		return ethAmountInUsd;
	}

	function getEntranceFee() public view returns (uint256) {
		uint256 minimumUSD = 50 * 10**18;
		uint256 price = getPrice();
		uint256 precision = 1 * 10**18;
		return ((minimumUSD * precision) / price) + 1;
	}

	modifier onlyOwner() {
		require(msg.sender == owner);
		_;
	}

	function withdraw() public payable onlyOwner {
		msg.sender.transfer(address(this).balance);
		for (uint256 funderIndex = 0;funderIndex < funders.length;funderIndex++){
			address funder = funders[funderIndex];
			addressToAmountFunded[funder] = 0;
		}
		funders = new address[](0);
	}
}


Notice that in the above contract, we have defined AggregatorV3Interface public priceFeed and also a constructor for it as priceFeed = AggregatorV3Interface(_priceFeed). And later in the get price instead of Rinkeby eth_to_usd address code we have used this priceFeed variable to fetch ETH price.

3. Also, in the brownie-config.yaml, we enter this networks declaration:


networks:
	default: development
	rinkeby:
		eth_usd_price_feed: '0x8A753747A1Fa494EC906cE90E9f37563A8AF630e'
		verify: True
	mainnet-fork-dev:
		eth_usd_price_feed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'
		verify: False
	development:
		verify: False
	ganache-local:
		verify: False


Here, we define all kinds of price feeds related to Mainnet and Rinkeby. Also, define development and ganache-local networks. Next to every network name, we define whether it is going to be verified for publishing or not.

4. In the helpful_scripts.py, we write:


from brownie import network, config, accounts, MockV3Aggregator
from web3 import Web3

FORKED_LOCAL_ENVIRONMENTS = ["mainnet-fork", "mainnet-fork-dev"]
LOCAL_BLOCKCHAIN_ENVIRONMENTS = ["development", "ganache-local"]

DECIMALS = 8
STARTING_PRICE = 200000000000

def get_account():
	if (network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS or network.show_active() in 																		 
        		FORKED_LOCAL_ENVIRONMENTS):
		return accounts[0]
	else:
		return accounts.add(config["wallets"]["from_key"])

def deploy_mocks():
	print(f"The active network is {network.show_active()}")
	print("Deploying Mocks...")
	if len(MockV3Aggregator) <= 0:
		MockV3Aggregator.deploy(DECIMALS, STARTING_PRICE, {"from": get_account()})
		print("Mocks Deployed!")


In this helpful_scripts.py file, we have defined all networks and helped the deploy.py choose the proper account according to the network that is currently active. We have also defined another function for the deploy_mocks.py file, which is going to be explained later.

4. Inside the scripts folder, create a file named deploy_mocks.py and paste the below scripts in it. Use this script if you want to deploy mocks to a Testnet:


from brownie import ( MockV3Aggregator, network,)
from scripts.helpful_scripts import (get_account,)

DECIMALS = 8
INITIAL_VALUE = 200000000000

def deploy_mocks():

	print(f"The active network is {network.show_active()}")
	print("Deploying Mocks...")
	account = get_account()
	MockV3Aggregator.deploy(DECIMALS, INITIAL_VALUE, {"from": account})
	print("Mocks Deployed!")

def main():
	deploy_mocks()


5. Inside the scripts folder create a new file called, fund_and_withdraw.py and paste these scripts in it:


from brownie import FundMe
from scripts.helpful_scripts import get_account

def fund():
	fund_me = FundMe[-1]
	account = get_account()
	entrance_fee = fund_me.getEntranceFee()
	print(entrance_fee)
	print(f"The current entry fee is {entrance_fee}")
	print("Funding")
	fund_me.fund({"from": account, "value": entrance_fee})

def withdraw():
	fund_me = FundMe[-1]
	account = get_account()
	fund_me.withdraw({"from": account})

def main():
	fund()
	withdraw()


Using the above script, we can interact with our own contract without the need to use the Etherscan interface for our contract. We can fund the contract and withdraw from it.

6. And in the end, it is finally the time to modify deploy.py:


from brownie import FundMe, MockV3Aggregator, network, config
from scripts.helpful_scripts import (
	get_account,
	deploy_mocks,
	LOCAL_BLOCKCHAIN_ENVIRONMENTS,
	)

def deploy_fund_me():
	account = get_account()
	if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
		price_feed_address = config["networks"][network.show_active()]["eth_usd_price_feed"]
	else:
		deploy_mocks()
		price_feed_address = MockV3Aggregator[-1].address

	fund_me = FundMe.deploy( price_feed_address,{"from": account},publish_source=config["networks"]
		[network.show_active()].get("verify"),)
	print(f"Contract deployed to {fund_me.address}")
	return fund_me

def main():
	deploy_fund_me()


The above deploy.py script which has been integrated to work with different networks, first checks which network we are in. Then, it fetches the price feed. And then, it deploys the contract using the price feed address, an account that is chosen according to the active network, and the verification state-related whether we want to publish the contract or not that has been declared in brownie-config.yaml. And then we finally deploy the contract. In the next part of this tutorial, we are going to run this project and see if it works properly.

Python web3 tools

Need More Python Web3 Understanding?

If you're having hard time understanding what's going on in this article, you probably missed our article explaining how to deploy a smart contract using Python web3 tools. By reading it, this article will become much easier.

Arashtad Serivces
We can help you on 3d applications and blockchain developement
Let Us Know What You Need
Blockchain Development

Crowdfunding Smart Contract: Testing the Scripts

In this article, we are going to write the test scripts related to the deployment of the Fundme.sol smart contract we wrote earlier in the previous article. This testing process is going to be applied on the Ganache simulated blockchain which is local. Ganache is the best network that can be used for testing.
For running and testing our deployment, we need to create a test_fund_me.py file inside the test folder and paste the following code in it:


from scripts.helpful_scripts import get_account, LOCAL_BLOCKCHAIN_ENVIRONMENTS
from scripts.deploy import deploy_fund_me
from brownie import network, accounts, exceptions
import pytest

def test_can_fund_and_withdraw():
	account = get_account()
	fund_me = deploy_fund_me()
	entrance_fee = fund_me.getEntranceFee() + 100
	tx = fund_me.fund({"from": account, "value": entrance_fee})
	tx.wait(1)
	assert fund_me.addressToAmountFunded(account.address) == entrance_fee
	tx2 = fund_me.withdraw({"from": account})
	tx2.wait(1)
	assert fund_me.addressToAmountFunded(account.address) == 0

	def test_only_owner_can_withdraw():
	if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
		pytest.skip("only for local testing")
		fund_me = deploy_fund_me()
		bad_actor = accounts.add()
		with pytest.raises(exceptions.VirtualMachineError):
			fund_me.withdraw({"from": bad_actor})



Also, do not forget to install pytest.by:

pip install pytest

Now, if we want to compile our project, in the console we write:

brownie compile

The result should be something like this:

Brownie v1.18.1 - Python development framework for Ethereum Compiling contracts... Solc version: 0.6.12 Optimizer: Enabled Runs: 200 EVM Version: Istanbul Generating build data... - smartcontractkit/[email protected]/AggregatorInterface - smartcontractkit/[email protected]/AggregatorV2V3Interface - smartcontractkit/[email protected]/AggregatorV3Interface - MockV3Aggregator Project has been compiled. Build artifacts saved at/home/mohamad/brownie_fund_me/build/contracts

And now, to discover all of the brownie networks lists, we type:

brownie networks list

Result:

Brownie v1.18.1 - Python development framework for Ethereum The following networks are declared: Ethereum ├─Mainnet (Infura): mainnet ├─Ropsten (Infura): ropsten ├─Rinkeby (Infura): rinkeby ├─Goerli (Infura): goerli └─Kovan (Infura): kovan Ethereum Classic ├─Mainnet: etc └─Kotti: kotti Arbitrum └─Mainnet: arbitrum-main Avalanche ├─Mainnet: avax-main └─Testnet: avax-test Aurora ├─Mainnet: aurora-main └─Testnet: aurora-test Binance Smart Chain ├─Testnet: bsc-test └─Mainnet: bsc-main Fantom Opera ├─Testnet: ftm-test └─Mainnet: ftm-main Harmony └─Mainnet (Shard 0): harmony-main Moonbeam └─Mainnet: moonbeam-main Optimistic Ethereum ├─Mainnet: optimism-main └─Kovan: optimism-test Polygon ├─Mainnet (Infura): polygon-main └─Mumbai Testnet (Infura): polygon-test XDai ├─Mainnet: xdai-main └─Testnet: xdai-test Development ├─Ganache-CLI: development ├─Geth Dev: geth-dev ├─Hardhat: hardhat ├─Hardhat (Mainnet Fork): hardhat-fork ├─Ganache-CLI (Mainnet Fork): mainnet-fork ├─Ganache-CLI (BSC-Mainnet Fork): bsc-main-fork ├─Ganache-CLI (FTM-Mainnet Fork): ftm-main-fork ├─Ganache-CLI (Polygon-Mainnet Fork): polygon-main-fork ├─Ganache-CLI (XDai-Mainnet Fork): xdai-main-fork ├─Ganache-CLI (Avax-Mainnet Fork): avax-main-fork └─Ganache-CLI (Aurora-Mainnet Fork): aurora-main-fork

Now, we should add Ganache to Ethereum networks, to be able to keep track of our transactions inside the deployments folder. To do that, according to our host address and chainid, we write:

brownie networks add Ethereum ganache-local host=http://127.0.0.1:7545 chainid=5777

Result:

Brownie v1.18.1 - Python development framework for Ethereum SUCCESS: A new network 'ganache-local' has been added └─ganache-local ├─id: ganache-local ├─chainid: 5777 └─host: http://127.0.0.1:7545

And it has successfully been added. Now to make sure, again we write in the console:

brownie networks list

Result:

Brownie v1.18.1 - Python development framework for Ethereum The following networks are declared: Ethereum ├─Mainnet (Infura): mainnet ├─Ropsten (Infura): ropsten ├─Rinkeby (Infura): rinkeby ├─Goerli (Infura): goerli ├─Kovan (Infura): kovan └─ganache-local: ganache-local ………………………..

We can see that ganache-local has been added to the Ethereum networks list.
Now, in order to run our deploy.py on ganache-local:

brownie run scripts/deploy.py --network ganache-local result: Brownie v1.18.1 - Python development framework for Ethereum Compiling contracts... Solc version: 0.6.12 Optimizer: Enabled Runs: 200 EVM Version: Istanbul Generating build data... - smartcontractkit/[email protected]/AggregatorV3Interface - smartcontractkit/[email protected]/SafeMathChainlink - FundMe BrownieFundMeProject is the active project. Running 'scripts/deploy.py::main'... The active network is ganache-local Deploying Mocks... Mocks Deployed! Transaction sent: 0xd9abd015320007e15ba8ab3e33b64e685986e0b277a0d5f9bab41cf8449f72ee Gas price: 20.0 gwei Gas limit: 446315 Nonce: 1 FundMe.constructor confirmed Block: 2 Gas used: 405741 (90.91%) FundMe deployed at: 0xEd48d45970A4CB5541fffCf3a5ed5cB061435E1A Contract deployed to 0xEd48d45970A4CB5541fffCf3a5ed5cB061435E1A

And we can track the transaction on Ganache.

crowdfunding smart contract

Also, see the records on build/deployments folder (Notice the 5777 as the chain id and the corresponding .json files).

crowdfunding smart contract

The rest of our code execution will be continued in the next part.

Crowdfunding Smart Contract: Running A Specific Network

In this tutorial, we try to connect to Mainnet-fork dev to complete the list of networks that we can connect to. We also try to execute the fund and withdraw transactions and put it to the test. If we want to use a development network other than the persistent one, we can copy the HTTP address from alchemy.io and the Ganache CLI to be able to connect to a development network other than the Infura host node.

We continue our crowdfunding deployment execution here.
The other networks can be run with:

brownie run scripts/deploy.py --network

Also, as declared in brownie-config.yaml, the default network is development which is Ganache, so by running:

brownie run scripts/deploy.py

We will get:

Brownie v1.18.1 - Python development framework for Ethereum BrownieFundMeProject is the active project. Launching 'ganache-cli --chain.vmErrorsOnRPCResponse true --wallet.totalAccounts 10 --hardfork istanbul --miner.blockGasLimit 12000000 --wallet.mnemonic brownie --server.port 8545'... Running 'scripts/deploy.py::main'... The active network is development Deploying Mocks... Transaction sent: 0xb7fcc22911055aa0e06bb329d0b366065e4c01e37827c19975048cb8324cb581 Gas price: 0.0 gwei Gas limit: 12000000 Nonce: 0 MockV3Aggregator.constructor confirmed Block: 1 Gas used: 430659 (3.59%) MockV3Aggregator deployed at: 0x3194cBDC3dbcd3E11a07892e7bA5c3394048Cc87 Mocks Deployed! Transaction sent: 0x32cc5492fa66ebb172a52a3a8c83ae6ed230a28738034bd62ce52de3acb71cae Gas price: 0.0 gwei Gas limit: 12000000 Nonce: 1 FundMe.constructor confirmed Block: 2 Gas used: 405741 (3.38%) FundMe deployed at: 0x602C71e4DAC47a042Ee7f46E0aee17F94A3bA0B6 Contract deployed to 0x602C71e4DAC47a042Ee7f46E0aee17F94A3bA0B6 Terminating local RPC client…

Executing fund and withdraw

Now, it is time to interact with our contract by funding and withdrawing using the scripts/fund_and_withdraw.py, So to do that, in the terminal, we type:

brownie run scripts/fund_and_withdraw.py --network ganache-local

Result:

Brownie v1.18.1 - Python development framework for Ethereum BrownieFundMeProject is the active project. Running 'scripts/fund_and_withdraw.py::main'... 25000000000000001 The current entry fee is 25000000000000001 Funding Transaction sent: 0x6372f7d40f64544b802675b25e8a7c0f6ae70ee6fc56868600bc2941812c0eb2 Gas price: 20.0 gwei Gas limit: 99258 Nonce: 2 FundMe.fund confirmed Block: 3 Gas used: 90235 (90.91%) Transaction sent: 0xf5a0409e0a852cc9f3c4965619d6183013321ca6010f96537172b51159672ba3 Gas price: 20.0 gwei Gas limit: 76963 Nonce: 3 FundMe.withdraw confirmed Block: 4 Gas used: 24967 (32.44%)

And we can see that both fund and withdraw transactions have been successfully executed. If we look at the Ganache transactions, we will be able to see the track of the transactions:

crowdfunding smart contract

It is now time to test the project by running the following command in the terminal:

brownie test

Result:

Brownie v1.18.1 - Python development framework for Ethereum ============================================= test session starts ============================================== platform linux -- Python 3.8.10, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: /home/mohamad/brownie_fund_me plugins: eth-brownie-1.18.1, web3-5.27.0, xdist-1.34.0, forked-1.4.0, hypothesis-6.27.3 collected 2 items Launching 'ganache-cli --chain.vmErrorsOnRPCResponse true --wallet.totalAccounts 10 --hardfork istanbul --miner.blockGasLimit 12000000 --wallet.mnemonic brownie --server.port 8545'... tests/test_fund_me.py .. [100%] ============================================== 2 passed in 2.59s =============================================== Terminating local RPC client...

And we see that the tests are passed, which shows both funds and withdraw functions work correctly and also only the owner can withdraw.

Adding a Development Network

Now, it is time to add a development network instead of a persistent network and we use a host node other than Infura. To do that, we should head over to the alchemy.io link and sign up or log in.

Arashtad smart contract

There are some steps that you need to take. And after you enter your profile, press the create app button:

Arashtad smart contract

Then, create a Mainnnet development Ethereum app (enter any name you like in the 2 boxes).

Arashtad smart contract

Then, enter the app and click on the view key on top of the page.

Arashtad smart contract

Copy the HTTP address and paste it into the fork section of the below command:

brownie networks add development mainnet-fork-dev cmd=ganache-cli host=http://127.0.0.1 fork=https://eth-mainnet.alchemyapi.io/v2/pGl-uSqPKVYCu4IpI1bjpK6dzxmLImD4 accounts=10 mnemonic=brownie port=8545

After you hit enter, the result will be:

Brownie v1.18.1 - Python development framework for Ethereum SUCCESS: A new network 'mainnet-fork-dev' has been added └─mainnet-fork-dev ├─id: mainnet-fork-dev ├─cmd: ganache-cli ├─cmd_settings: {'fork': 'https://eth-mainnet.alchemyapi.io/v2/pGl-uSqPKVYCu4IpI1bjpK6dzxmLImD4', 'accounts': 10, 'mnemonic': 'brownie', 'port': 8545} └─host: http://127.0.0.1

And there we go. We have successfully added the Mainnet fork dev network. Congratulations! You have finally completed the crowdfunding project that can be run on different networks.

Conclusion:

In this tutorial, we have worked on the different scripts that we need to set up the crowdfunding project using Brownie. If you have read our article on writing the Fundme.sol smart contract in Remix IDE, you must be familiar with how the structure of the smart contract. Here, to make scripts more organized, we have added other python files such as helpful_scripts.py to manage the accounts from different networks, deploy_mocks.py, fund_and_withdraw.py, and also brownie_config.yaml to categorize the networks and the necessary data related to them.
In this article, we have written the test scripts necessary to test the deployment of the smart contract. For the testing, we have used the Ganache simulated blockchain which is local and thus the best option for applying different tests in the smart contracts.
In this article, we have managed to connect to Mainnet fork dev to complete the list of networks that we can connect to. We also have also tried to execute the fund and withdraw transactions and put it to the test. If we want to use a development network other than the persistent one, we can copy the HTTP address from alchemy.io and the Ganache CLI to be able to connect to a development network other than the Infura host node.

Download this Article in PDF format

metaverse

We Are Working on Metaverses

Metaverses, 3d modeling, 3d application, 3d websites, and even animations are just some of our vase expertise.

Arashtad Serivces
Tell us about your ideas
Fill in the Form
Blockchain Development

Using Brownie for Interacting with Aave Protocol (Borrowing & Repaying)

This article is about what to do for using Brownie for Aave protocol after depositing WETH in the Aave lending pool. In our next step, we will try to borrow some Dai. To do this, we should add some dependency contracts to the contracts folder such as AggregatorV3Interface.sol and LinkTokenInterface.sol. We should also modify the deploy.py and brownie-config.yaml files to adapt to our new functionality.

Adding the necessary contracts to the contracts folder

In this 3rd part of the tutorial, after depositing ETH into the pool, it is time to borrow some DAI using our WETH collateral.
There are 2 interfaces to add to the interfaces folder:

    1. AggregatorV3Interface.sol
    2. LinkTokenInterface.sol


pragma solidity ^ 0.6.6;

interface LinkTokenInterface {
	function allowance(address owner, address spender) external view returns (uint256 remaining);
	function approve(address spender, uint256 value) external returns (bool success);
	function balanceOf(address owner) external view returns (uint256 balance);
	function decimals() external view returns (uint8 decimalPlaces);
	function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
	function increaseApproval(address spender, uint256 subtractedValue) external;
	function name() external view returns (string memory tokenName);
	function symbol() external view returns (string memory tokenSymbol);
	function totalSupply() external view returns (uint256 totalTokensIssued);
	function transfer(address to, uint256 value) external returns (bool success);
	function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool 				 
		success);
	function transferFrom(address from, address to, uint256 value) external returns (bool success);
}



Modifying the Deploy.py

In the last part we went up to depositing WETH.



def main():
	account = get_account()
	erc20_address = config["networks"][network.show_active()]["weth_token"]
	if network.show_active() in ["mainnet-fork"]:
		get_weth(account=account)
	lending_pool = get_lending_pool()
	approve_erc20(amount, lending_pool.address, erc20_address, account)
	print("Depositing...")
	lending_pool.deposit(erc20_address, amount, account.address, 0, {"from": account})
	print("Deposited!")


We continue the def main () like this to borrow DAI:


borrowable_eth, total_debt_eth = get_borrowable_data(lending_pool, account)
	print(f"LETS BORROW IT ALL")
	erc20_eth_price = get_asset_price()
	amount_erc20_to_borrow = (1 / erc20_eth_price) * (borrowable_eth * 0.95)
	print(f"We are going to borrow {amount_erc20_to_borrow} DAI")
	borrow_erc20(lending_pool, amount_erc20_to_borrow, account)
	borrowable_eth, total_debt_eth = get_borrowable_data(lending_pool, account)


The above process includes:

    1. Getting the data of how much we can borrow based on how much we have deposited and how much debt we have.
    2. Getting the price of the asset we are going to borrow
    3. Calculating the amount that we are going to borrow (it is multiplied by 0.95 as we can only borrow 95 percent of our collateral at most.)
    4. Borrowing the DAI.


def get_borrowable_data(lending_pool, account):
		(total_collateral_eth,
		total_debt_eth,
		available_borrow_eth,
		current_liquidation_threshold,
		tlv,
		health_factor, ) = lending_pool.getUserAccountData(account.address)
	available_borrow_eth = Web3.fromWei(available_borrow_eth, "ether")
	total_collateral_eth = Web3.fromWei(total_collateral_eth, "ether")
	total_debt_eth = Web3.fromWei(total_debt_eth, "ether")
	print(f"You have {total_collateral_eth} worth of ETH deposited.")
	print(f"You have {total_debt_eth} worth of ETH borrowed.")
	print(f"You can borrow {available_borrow_eth} worth of ETH.")
	return (float(available_borrow_eth), float(total_debt_eth))


The above function retrieves the data related to how much we can borrow based on our account and the lending pool we have deposited our money.


def borrow_erc20(lending_pool, amount, account, erc20_address=None):
	erc20_address = (
	erc20_address
	if erc20_address
	else config["networks"][network.show_active()]["aave_dai_token"])
	transaction = lending_pool.borrow(
		erc20_address,
		Web3.toWei(amount, "ether"),
		1,
		0,
		account.address,
		{"from": account},
		)
	transaction.wait(1)
	print(f"Congratulations! We have just borrowed {amount}")


The above function executes the borrowing.


def get_asset_price():
	dai_eth_price_feed = interface.AggregatorV3Interface(
		config["networks"][network.show_active()]["dai_eth_price_feed"])
	latest_price = Web3.fromWei(dai_eth_price_feed.latestRoundData()[1], 														 
		"ether")
	print(f"The DAI/ETH price is {latest_price}")
	return float(latest_price)


Using the above function, we get the DAI/ETH pair price.

Brownie_config.yaml

The complete brownie-config.yaml file goes like this:


dependencies:
	- smartcontractkit/[email protected]
	- aave/[email protected]
compiler:
	solc:
		remappings:
			- "@chainlink=smartcontractkit/chainlink-brownie-												[email protected]"
			- "@aave=aave/[email protected]"
autofetch_sources: True
dotenv: .env
verify: False
networks:
	default: mainnet-fork
	mainnet-fork:
		lending_pool_addresses_provider: "0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5"
		weth_token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
		link_token: "0x514910771af9ca656af840dff83e8264ecf986ca"
		aave_link_token: "0x514910771af9ca656af840dff83e8264ecf986ca"
		aave_dai_token: "0x6b175474e89094c44da98b954eedeac495271d0f"
		dai_token: "0x6b175474e89094c44da98b954eedeac495271d0f"
		link_eth_price_feed: "0xDC530D9457755926550b59e8ECcdaE7624181557"
		dai_eth_price_feed: "0x773616E4d11A78F511299002da57A0a94577F1f4"
	kovan:
		vrf_coordinator: "0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9"
		aave_link_token: "0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789"
		aave_dai_token: "0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD"
		link_token: "0xa36085F69e2889c224210F603D836748e7dC0088"
		keyhash: "0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
		fee: 100000000000000000
		oracle: "0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e"
		jobId: "29fa9aa13bf1468788b7cc4a500a45b8"
		eth_usd_price_feed: "0x9326BFA02ADD2366b30bacB125260Af641031331"
		link_eth_price_feed: "0x3Af8C569ab77af5230596Acf0E8c2F9351d24C38"
		dai_eth_price_feed: "0x22B58f1EbEDfCA50feF632bD73368b2FdA96D541"

		lending_pool_addresses_provider: "0x88757f2f99175387ab4c6a4b3067c77a695b0349"
		weth_token: "0xd0a1e359811322d97991e03f863a0c30c2cf029c"
wallets:
	from_key: ${PRIVATE_KEY}



Deploying the Contracts

Now, we can finally borrow our desired asset:

brownie run scripts/aave_borrow.py --network kovan

Result:

Brownie v1.18.1 - Python development framework for Ethereum AaveBrownieProject is the active project. Running 'scripts/aave_borrow.py::main'... Approving ERC20... Transaction sent: 0x0612e2c08897577cedef93950fb35d4e8710c29032d6ae5dcb0f202a27d9f3b2 Gas price: 2.500000007 gwei Gas limit: 50695 Nonce: 15 WETH9_.approve confirmed Block: 30943344 Gas used: 46087 (90.91%) WETH9_.approve confirmed Block: 30943344 Gas used: 46087 (90.91%) Approved! Depositing... Transaction sent: 0xf2fe4bb2e82189d2173cf7b147c24af47fa172061a0ac7c37a434ddc68bd984f Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 207906 Nonce: 16 Transaction confirmed Block: 30943347 Gas used: 176916 (85.09%) Deposited! You have 0.400410656100777314 worth of ETH deposited. You have 1.1287963056E-8 worth of ETH borrowed. You can borrow 0.320328513592658795 worth of ETH. LETS BORROW IT ALL The DAI/ETH price is 0.00030355 We are going to borrow 1002.5105844606354 DAI Transaction sent: 0xd1d8b7f23e2ea35eb12dc30f5142d5614068a652e77fa811c6830dde766f1f26 Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 353287 Nonce: 17 Transaction confirmed Block: 30943350 Gas used: 316618 (89.62%) This transaction already has 2 confirmations. Congratulations! We have just borrowed 1002.5105844606354 You have 0.400410804230975243 worth of ETH deposited. You have 0.304312101427770057 worth of ETH borrowed. You can borrow 0.016016541957010137 worth of ETH.

And as you can see we have got nearly 1002 DAI tokens as a result of borrowing from the Aave pool. Notice that the amount of deposited ETH is 0.4 which is the result of multiple times we have tested the deposit function and also a little more than 0.4 is because of the yield that Aave pool has considered for us as a result of depositing our ETH. In the next part, we are going to repay all of the borrowed DAI.

In this tutorial, after depositing WETH and borrowing Dai, it is time to repay back the funds we have deposited. To do this we will modify the deploy.py to completely do the 3 processes of swapping ETH for WETH, depositing WETH, borrowing DAI, and repaying the funds. As in the recent steps we hadn’t completely done the 4 tasks and as a result, we hadn’t repaid back the funds, we need to manually repay the remaining funds.

Modifying the deploy.py:

The final step of interacting with the Aave lending pool is to repay the DAI that we have borrowed. The complete steps of depositing, borrowing, and repaying back are included in this main function with the other functions we created in the recent parts:


def main():
	account = get_account()
	erc20_address = config["networks"][network.show_active()]["weth_token"]
	if network.show_active() in ["mainnet-fork"]:
		get_weth(account=account)
	lending_pool = get_lending_pool()
	approve_erc20(amount, lending_pool.address, erc20_address, account)
	print("Depositing...")
	lending_pool.deposit(erc20_address, amount, account.address, 0, {"from": account})
	print("Deposited!")
	borrowable_eth, total_debt_eth = get_borrowable_data(lending_pool, account)
	print(f"LETS BORROW IT ALL")
	erc20_eth_price = get_asset_price()
	amount_erc20_to_borrow = (1 / erc20_eth_price) * (borrowable_eth * 0.95)
	print(f"We are going to borrow {amount_erc20_to_borrow} DAI")
	borrow_erc20(lending_pool, amount_erc20_to_borrow, account)
	borrowable_eth, total_debt_eth = get_borrowable_data(lending_pool, account)



We continue the def main() with the following:



	repay_all(amount_erc20_to_borrow, lending_pool, account)
	get_borrowable_data(lending_pool, account)


And also, create a new function called repay_all:


def repay_all(amount, lending_pool, account):
	approve_erc20(Web3.toWei(amount, "ether"),
			lending_pool,
			config["networks"][network.show_active()]["aave_dai_token"],
			account,
			)
	tx = lending_pool.repay(
			config["networks"][network.show_active()]["aave_dai_token"],
			Web3.toWei(amount, "ether"),
			1,
			account.address,
			{"from": account},
			)
	tx.wait(1)
	print("Repaid!")



Deploying on the Kovan network:

Now, it is time to test the whole process:

brownie run scripts/aave_borrow.py --network kovan

Result:

Brownie v1.18.1 - Python development framework for Ethereum AaveBrownieProject is the active project. Running 'scripts/aave_borrow.py::main'... Approving ERC20... Transaction sent: 0x607f92b4795a1b344f27eb517b14b382b3af62060861bcb7e17fe56f2e49dbf4 Gas price: 2.500000007 gwei Gas limit: 50695 Nonce: 24 WETH9_.approve confirmed Block: 30944173 Gas used: 46087 (90.91%) WETH9_.approve confirmed Block: 30944173 Gas used: 46087 (90.91%) Approved! Depositing... Transaction sent: 0x8b19aae38d08356a19a336746530be83fb621e64c566d8777382f04dd97feb61 Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 207906 Nonce: 25 Transaction confirmed Block: 30944175 Gas used: 176916 (85.09%) Deposited! You have 0.600462332371017026 worth of ETH deposited. You have 0.395594815443779104 worth of ETH borrowed. You can borrow 0.084775050453034517 worth of ETH. LETS BORROW IT ALL The DAI/ETH price is 0.00030417 We are going to borrow 264.7739682755788 DAI Transaction sent: 0x114bf44d1ee6ca2490dbb32276e9f7abb91078c2b157c42edede91fbc331024d Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 330966 Nonce: 26 Transaction confirmed Block: 30944177 Gas used: 299518 (90.50%) This transaction already has 2 confirmations. Congratulations! We have just borrowed 264.7739682755788 You have 0.600462628542463152 worth of ETH deposited. You have 0.476131125542422592 worth of ETH borrowed. You can borrow 0.00423897729154793 worth of ETH. Approving ERC20... Transaction sent: 0x442a4ae4ee05339a7081fd4c91d231e71d9f30dfc489cc1ba511e3c64143587a Gas price: 2.500000007 gwei Gas limit: 31988 Nonce: 27 Transaction confirmed Block: 30944180 Gas used: 29080 (90.91%) Transaction confirmed Block: 30944180 Gas used: 29080 (90.91%) Approved! Transaction sent: 0x20529c85bc1852bce18341ed3404094ba1af3db58f81ade3145edea7afefb330 Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 242655 Nonce: 28 Transaction confirmed Block: 30944181 Gas used: 212817 (87.70%) Transaction confirmed Block: 30944181 Gas used: 212817 (87.70%) Repaid! You have 0.60046299875677081 worth of ETH deposited. You have 0.395594844442992547 worth of ETH borrowed. You can borrow 0.084775554562424101 worth of ETH.

As you can see, we have successfully deposited WETH, borrowed some DAI, and repaid what we have borrowed. Now let’s check our Metamask wallet.

Repaying all funds:

You might wonder why we still have some DAI in it. The reason is that, in our recent code run, we didn’t have to repay. As a result, we still have some of the DAIs that we haven’t repaid back. To do so, change the main function to:


def main():
	account = get_account()
	erc20_address = config["networks"][network.show_active()]["weth_token"]
	if network.show_active() in ["mainnet-fork"]:
		get_weth(account=account)
	lending_pool = get_lending_pool()
	approve_erc20(amount, lending_pool.address, erc20_address, account)
	borrowable_eth, total_debt_eth = get_borrowable_data(lending_pool, account)
	amount_erc20_to_repay =  # enter the remaining to repay


We should determine the amount we want to repay in the amount_erc20_to_repay.


repay_all(amount_erc20_to_repay, lending_pool, account)
get_borrowable_data(lending_pool, account)


Or instead, you can repay manually using the Aave interface:

Click repay next to DAI and then select max under the DAI icon in the pop-up window, and click approve, after that confirm the Metamask pop-up:

Now, you can repay DAI:

Confirm Metamask pop-up again:

You can also withdraw by following the steps in the below photos. Notice that for both repay and withdraw you need to get approval from your Metamask wallet and click confirm and then repay or withdraw.

Conclusion

In this article, we have managed to borrow some Dai from the Aave lending pool. To do this, we have added some dependency contracts like LinkTokenInterface.sol and AggregatorV3Interface.sol. We have also modified the deploy.py file to do the borrowing function for us.
In this tutorial, we have managed to do the complete process of the Aave lending pool, meaning that we have swapped ETH for WETH, deposited WETH, borrowed Dai, and finally repaid borrowed Dai using Brownie python tools.

Download this Article in PDF format

3d animation

Check Out Our Services

In Arashtad, we’re working on 3D games, metaverses, and other types of WebGL and 3D applications with our 3D web development team. However, our services are not limited to these. Back-end developments, front-end developments, 3d modeling, and animations are in our arsenal too.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
Blockchain Development

Using Python Framework Brownie for Interacting with Aave Protocol

In this tutorial, regarding the Aave protocol, we are going to interact with the Aave protocol using Brownie. The first step is to swap ETH with WETH which is necessary when we want to deal with Aave. This lending and borrowing protocol, accept WETH instead of ETH. We add WETH (Wrapped Ethereum) to our Metamask wallet and also create the project folder for interacting with the Aave protocol. After the first (which was swapping ETH with WETH), it is now time to deposit our WETH. To do this, we will download some solidity scripts related to the Aave lending pool, and paste them into the contracts directory of the project folder. Finally, modify the deploy.py to also activate the depositing contracts.

Interacting with Aave Protocol by Using Brownie

This series of tutorials is the continuation of How to deploy a smart contract using python web3 tools in addition to solidity, smart contracts, and brownie python tools. As a result, it is highly recommended that before you start this tutorial, be familiar with the python web3 and smart contracts. In the last tutorial, we learned how to interact with the Aave protocol using the interface provided at this link. In this part, we are going to do the same interactions using python scripts.
These interactions include:

    1. Swapping ETH with WETH (Wrapped ETH).
    2. Depositing WETH into Aave.
    3 Using WETH collateral to borrow DAI
    4. Paying back the borrowed DAI

Creating the Project

So, like every project, we begin with: mkdir aave_brownie
cd aave_brownie
code .
Brownie init

The first thing you should do to interact with the Aave protocol is to deposit some ETH into Aave. When you do this, the actual thing that happens is that ETH is swapped into the ERC-20 version of Ethereum, called WETH ( Wrapped Ethereum). Because in our project we use the Kovan network, we should copy the address of the contract from this link and paste it into our config file (brownie-config.yaml).

using Brownie for Aave protocol

If you go to write the contract, you will see an actual interface of the WETH contract for deposit and withdrawal.

using Brownie for Aave protocol

Now, let’s write our scripts, we begin with creating a file called get_weth.py in the scripts folder:


from brownie import accounts, config, network, interface
from scripts.helpful_scripts import get_account

def main():
	get_weth()

def get_weth(account=None):
	account = get_account()
	weth = interface.Weth(
	config["networks"][network.show_active()]["weth_token"])
	tx = weth.deposit({"from": account, "value": 0.1 * 1e18})
	print("Received 0.1 WETH")
	return tx


Use the helpful_scripts.py to get the proper account in the scripts folder:


from brownie import network, config, accounts
def get_account():
	if network.show_active() in ["hardhat", "development", "mainnet-fork"]:
		return accounts[0]
	if network.show_active() in config["networks"]:
		account = accounts.add(config["wallets"]["from_key"])
	return account
	return None



pragma solidity ^ 0.4.19;

interface Weth {
	function allowance(address owner, address spender) external view returns (uint256 remaining);
	function approve(address spender, uint256 value) external returns (bool success);
	function balanceOf(address owner) external view returns (uint256 balance);
	function decimals() external view returns (uint8 decimalPlaces);
	function name() external view returns (string memory tokenName);
	function symbol() external view returns (string memory tokenSymbol);
	function totalSupply() external view returns (uint256 totalTokensIssued);
	function transfer(address to, uint256 value) external returns (bool success);
	function transferFrom(address from, address to, uint256 value) external returns(bool success);
	function deposit() external;
	function withdraw(uint wad) external;
}


And an interface named IWeth.sol in the interface folder (you can notice that it has the methods and events of an ERC20 token):


dotenv: .env
networks:
	mainnet-fork:
		weth_token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"

	kovan:
		weth_token: "0xd0a1e359811322d97991e03f863a0c30c2cf029c"
wallets:
	from_key: ${PRIVATE_KEY}


Also, enter your private key and Infura ID in the .env file, in the main directory:


export WEB3_INFURA_PROJECT_ID=' your Infura ID'
export PRIVATE_KEY=' Your private key '


It is now time to run our project on the Kovan test network to swap ETH with WETH:

brownie run scripts/get_weth.py --network kovan

Result:

Brownie v1.18.1 - Python development framework for Ethereum AaveBrownieProject is the active project. Running 'scripts/get_weth.py::main'... Transaction sent: 0x96955d6833e1ceb11e8de71d8c64cffd4af84765ceb7c333e6fa666c2f2e21f5 Gas price: 2.500000007 gwei Gas limit: 49572 Nonce: 7 WETH9_.deposit confirmed Block: 30924833 Gas used: 45066 (90.91%) Received 0.1 WETH

To make sure we have actually received the desired WETH, let’s head over to our Metamask and import WETH token by pasting the address of WETH Kovan contract in the Token Contract Address box:

using Brownie for Aave protocol

And there we go! We have 0.1 WETH in our account in exchange for 0.1 ETH.

brownie

And there we go! We have 0.1 WETH in our account in exchange for 0.1 ETH.

brownie

After our first approach towards using Brownie for Aave protocol (which was swapping ETH with WETH), it is now time to deposit our WETH. To do this, we will download some solidity scripts related to the Aave lending pool, and paste them into the contacts directory of the project folder. And finally, modify the deploy.py to also activate the depositing contracts.

Depositing WETH

After having successfully swapped ETH with WETH, it is time to deposit our WETH to the lending pool, so let’s keep the scripts we added to our project, and add some more files to be able to do this task. First and foremost, we need to export our Etherscan API key in the .env file:


export ETHERSCAN='Your Etherscan API key'

The next thing we need to do is to add some interfaces to the interfaces folder from the Aave GitHub repository. These files include:

    1. ILendingPoolAddressesProvider.sol
    2. ILendingPool.sol

Notice that you should modify lines 5 and 6 in the code to be able to use it in your directory:


import {ILendingPoolAddressesProvider} from 	 
	'@aave/contracts/interfaces/IlendingPoolAddressesProvider.sol';
import {DataTypes} from '@aave/contracts/protocol/libraries/types/DataTypes.sol';


Besides, in the brownie-config.yaml, add these lines:


dependencies:
	- smartcontractkit/[email protected]
	- aave/[email protected]
compiler:
	solc:
		remappings:
			- "@chainlink=smartcontractkit/[email protected]"
			- "@aave=aave/[email protected]"


IERC20.sol

We also need to paste in ERC-20 smart contract in the contracts directory:


pragma solidity ^ 0.6.6;

interface IERC20 {
	function allowance(address owner, address spender) external view returns (uint256 remaining);
	function approve(address spender, uint256 value) external returns (bool success);
	function balanceOf(address owner) external view returns (uint256 balance);
	function decimals() external view returns (uint8 decimalPlaces);
	function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
	function increaseApproval(address spender, uint256 subtractedValue) external;
	function name() external view returns (string memory tokenName);
	function symbol() external view returns (string memory tokenSymbol);
	function totalSupply() external view returns (uint256 totalTokensIssued);
	function transfer(address to, uint256 value) external returns (bool success);
	function transferFrom(address from, address to, uint256 value) external returns (bool success);
}


brownie_config.yaml:

In the brownie-config.yaml file, we also need to add some specifications about the networks:


networks:
	default: mainnet-fork
	mainnet-fork:
		lending_pool_addresses_provider: "0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5"
		weth_token: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
	kovan:
		lending_pool_addresses_provider: "0x88757f2f99175387ab4c6a4b3067c77a695b0349"
		weth_token: "0xd0a1e359811322d97991e03f863a0c30c2cf029c"


aave_borrow.py

And finally we create a file called aave_borrow.py to start our depositing process:


from brownie import accounts, config, interface, network
from web3 import Web3
from scripts.get_weth import get_weth
from scripts.helpful_scripts import get_account

amount = Web3.toWei(0.1, "ether")


The above function will convert 0.1 ether into a Wei unit. We use this conversion to avoid writing many zeros after 1.


def main():
	account = get_account()
	erc20_address = config["networks"][network.show_active()]["weth_token"]
	if network.show_active() in ["mainnet-fork"]:
		get_weth(account=account)
	lending_pool = get_lending_pool()
	approve_erc20(amount, lending_pool.address, erc20_address, account)
	print("Depositing...")
	lending_pool.deposit(erc20_address, amount, account.address, 0, {"from": account})
	print("Deposited!")


The above function will get the account address depending on the active network and then gets the ERC-20 address of the WETH token according to the chosen network and then gets some WETH token if the Mainnet-fork network is active (remember in the last tutorial we got some WETH in the Kovan network but not in the Mainnet-fork). After that, we will get the lending pool using the function get_lending_pool(). We also approve the ERC-20 transaction using the approve_erc20 function and in the end, we deposit the WETH in the lending pool.


def get_lending_pool():
	lending_pool_addresses_provider = interface.ILendingPoolAddressesProvider(
		config["networks"][network.show_active()]["lending_pool_addresses_provider"])
	lending_pool_address = lend-ing_pool_addresses_provider.getLendingPool()
	lending_pool = interface.ILendingPool(lending_pool_address)
	return lending_pool


The above function uses the address of the lending pool according to the active network and then returns the lending pool according to the address. Notice that we use the function of the IlendingPoolAddressesProvider.sol file.


def approve_erc20(amount, lending_pool_address, erc20_address, account):
	print("Approving ERC20...")
	erc20 = interface.IERC20(erc20_address)
	tx_hash = erc20.approve(lending_pool_address, amount, {"from": account})
	tx_hash.wait(1)
	print("Approved!")
	return True


The above function will approve the ERC-20 using the IERC20.sol file.


if __name__ == "__main__":
	main()


Compiling and Running the Project

After having set all files up, it is time to compile our project:

brownie compile

Result:

Brownie v1.18.1 - Python development framework for Ethereum Generating interface ABIs... Project has been compiled. Build artifacts saved at /home/mohamad/AAVE_brownie/build/contracts

Finally, we deposit the WETH into the lending pool on the Kovan network.

brownie run scripts/aave_borrow.py --network kovan

Result:

Brownie v1.18.1 - Python development framework for Ethereum AaveBrownieProject is the active project. Running 'scripts/aave_borrow.py::main'... Approving ERC20... Transaction sent: 0x0ea015becac17bb9f7a40dd6f93fbe8dd2043c8c41f35baf2158e5c9d58ce73a Gas price: 2.500000007 gwei Gas limit: 28805 Nonce: 12 WETH9_.approve confirmed Block: 30939584 Gas used: 26187 (90.91%) WETH9_.approve confirmed Block: 30939584 Gas used: 26187 (90.91%) Approved! Depositing... Transaction sent: 0x83cbdafc218186ee61a02097cd14dff42cce5dc1df4f2d66518d1b6fc6ab6501 Fetching source of 0x2646FcF7F0AbB1ff279ED9845AdE04019C907EBE from api-kovan.etherscan.io... Gas price: 2.500000007 gwei Gas limit: 207906 Nonce: 13 Transaction confirmed Block: 30939586 Gas used: 176916 (85.09%) Deposited!

As you can see, we have successfully deposited our 0.1 WETH into the Aave lending pool. In the next part, we are going to borrow some DAI from the pool.

Conclusion:

In this tutorial, we have managed to interact with the Aave protocol using Brownie. The first thing we did was to swap ETH with WETH which was a necessary step when we want to deal with Aave. This lending and borrowing protocol accepts WETH instead of ETH. We added WETH (Wrapped Ethereum) to our Metamask wallet and also created the project folder for interacting with the Aave protocol.
In this tutorial, we have downloaded the lending pool smart contract from the Aave protocol GitHub account and pasted them into our directory. In addition to that, we have modified the deploy.py file to deploy the depositing smart contracts as well as adding the aave_borrow.py file, and eventually, we have deposited the WETH we have in the Aave lending pool.

Download this Article in PDF format

metaverse

What Do We Do in Arashtad?

3D websites, 3D games, metaverses, and other types of WebGL and 3D applications are what we develop in our 3D web development team.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Request a Quote
ThreeJS Development

Introduction to Brownie-mix: A Boilerplate for Important Smart Contract Projects

In this article, we are going to get familiar with Brownie-mix as a boilerplate for blockchain projects in python. Using this boilerplate with the Brownie bake command will help you have so many of the dependency contracts provided for that specific project. There is also a complete brownie_config.yaml file provided with a complete list of networks. Some ready python files such as helpful_scripts.py and deploy_mocks.py are provided for you.

Introduction to the Brownie-mix

When we were examining how to deploy a smart contract using python web3 tools among our previous articles, we showed how to use Brownie. It is highly recommended that before you start this tutorial, be familiar with web3 python tools and also solidity language.
So far, we have coded most of our smart contract deployments using Brownie by starting like this in the terminal:

brownie init

And then some folders would have been created and then the rest of the project. But the hard part was that we needed to copy a lot of dependencies, such as the VRFConsumer.sol and other smart contracts, brownie-config.yaml file, helpful_scripts.py, deploy_mocks.py, and a lot of other useful scripts that we need to rewrite every time we created the project.
A Brownie-mix helps us cover this hard task and provides easy boilerplates for every type of project like DAO, NFTs, Token, ChainLink, and so on.

Brownie-mix

To Use Brownie-mix: Starting the Brownie Template

In order to use Brownie-mix boilerplates, we should first write the following command in the terminal:

brownie bake

In our case, for example, we want chainlink-mix (using which we have managed to write and deploy our contracts, so far).

brownie bake chainlink-mix
cd chainlink

And you will see that all the folders and files alongside all the necessary routine codes are provided for you in your directory called chainlink.

Brownie-mix

Modifying brownie_config.yaml

Notice that in the brownie-config.yaml, you should modify some parts:


# exclude SafeMath when calculating test coverage
# https://eth-brownie.readthedocs.io/en/v1.10.3/config.html#exclude_paths
reports:
	exclude_contracts:
		- SafeMath
dependencies:
	- smartcontractkit/[email protected]
	- OpenZeppelin/[email protected]
compiler:
	solc:
		remappings:
			- "@chainlink=smartcontractkit/[email protected]"
			- "@openzeppelin=OpenZeppelin/[email protected]"
# automatically fetch contract sources from Etherscan
autofetch_sources: True
# Uncomment to use the .env file
# dotenv: .env
# set a custom mnemonic for the development network
networks:
   default: development
   development:
		keyhash:"0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
		fee: 100000000000000000
		jobId: "29fa9aa13bf1468788b7cc4a500a45b8"
		update_interval: 60
		verify: False
   kovan:
	vrf_coordinator: "0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9"
	link_token: "0xa36085F69e2889c224210F603D836748e7dC0088"
	keyhash:"0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
	fee: 100000000000000000
	oracle: "0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8"
	jobId: "d5270d1c311941d0b08bead21fea7747"
	eth_usd_price_feed: "0x9326BFA02ADD2366b30bacB125260Af641031331"
	# Change to True if you have an Etherscan API key and want to verify
	verify: True
	update_interval: 60
   ganache:
	keyhash:"0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
	fee: 100000000000000000
	jobId: "29fa9aa13bf1468788b7cc4a500a45b8"
	update_interval: 60
	verify: False
	rinkeby:
	vrf_coordinator: "0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B"
	link_token: "0x01be23585060835e02b77ef475b0cc51aa1e0709"
	keyhash:"0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311"
	fee: 100000000000000000
	oracle: "0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8"
	jobId: "6b88e0402e5d415eb946e528b8e0c7ba"
	eth_usd_price_feed: "0x8A753747A1Fa494EC906cE90E9f37563A8AF630e"
	# Change to True if you have an Etherscan API key and want to verify
	verify: False
   fuji:
	link_token: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846"
	fee: 100000000000000000
	oracle: "0xcc80934eaf22b2c8dbf7a69e8e0d356a7cac5754"
	jobId: "5ca4fa9b2d64462290abfbda84e38cf4"
   mumbai:
	eth_usd_price_feed: "0x0715A7794a1dc8e42615F059dD6e406A6594651A"
	link_token: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB"
	vrf_coordinator: "0x8C7382F9D8f56b33781fE506E897a4F1e2d17255"
	keyhash:"0x6e75b569a01ef56d18cab6a8e71e6600d6ce853834d4a5748b720d06f878b3a4"
	fee: 1000000000000000000
   binance:
	# link_token: ??
	eth_usd_price_feed: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e"
   binance-fork:
	eth_usd_price_feed: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e"
   mainnet-fork:
	eth_usd_price_feed: "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"
   matic-fork:
	eth_usd_price_feed: "0xF9680D99D6C9589e2a93a78A04A279e509205945"
wallets:
	from_key: ${PRIVATE_KEY}
	from_mnemonic: ${MNEMONIC}



Notice that if you use mnemonic, you should use accounts.from_mnemonic to be able to use from_mnemonic and if you use the private key, you should use accounts.add instead.
Also, make sure to uncomment the dotenv: .env if you want to keep your private data somewhere safe.
By using the above .yaml file, you can use any networks that you want and be sure that there is nothing else needed to add to this file. In the contracts folder, you will also be able to see some useful contracts that work as a dependency. The most important folder is the scripts, inside which we have helpful_scripts.py, deploy_mocks.py, and some useful scripts that will help using them in your main deploy.py file.

Brownie-mix

As you can see, some of the important and useful functions of useful_scripts.py are as follows:


get_account

get_contract

fund_with_link

deploy_mocks


Using the above functions, you can write your test files and deploy.py file much easier.

Final Word on Brownie-mix

In this article, we have introduced Brownie-mixes as a boilerplate (template) for blockchain projects and provided guides on how to quickly modify them so that you can run your desired project instantly. These projects could be creating an ERC-20 token, NFT, Aave protocol, Chainlink, and so on.

Download this Article in PDF format

metaverse

Care to Know About Metaverse?

In Arashtad, we are providing custom services on 3d developments such as 3d websites, 3d models, metaverses and all 3d applications.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
Blockchain Development

How to Interact with the Aave Protocol Directly + Testnet User Interface

In this tutorial, regarding the Aave protocol, we are going to connect our Metamask to the Aave website to be able to interact with the Aave protocol directly. Then, we will switch to the Testnet. We will also get some Kovan ETH from the Chainlink Kovan faucet. Using the test ETH we have got, we will deposit it, withdraw Dai, and then finally pay back all the funds.

What Is Aave Protocol?

Aave is a decentralized finance (DeFi) protocol that allows us to borrow and lend our crypto assets. It provides tools to deposit our money and get some yields or borrow some money and repay whenever we want with a certain APY.
Now, we are going to first interact manually with the user interface at the Aave web app and then get into the code interaction with the Aave protocol.

Connecting Metamask to Aave:

First of all, you should connect your Metamask wallet to the Aave web app.

Interact with Aave Protocol

Then from the top right settings button, switch to Testnet mode

Interact with Aave Protocol

Getting Kovan ETH:

Also, don’t forget to get some Kovan ETH from this link:

Interact with Aave Protocol

Interacting with Aave Protocol Directly

Once your wallet is connected and you have got some kovan ETH, you will be able to see that your available asset on kovan test network is displayed on the webpage:

Interact with Aave Protocol

Now, in order to deposit or supply some ETH, Click supply and choose the amount of ETH you want to supply or lend. And then click Supply ETH.

Interact with Aave Protocol

You will see the Metamask pop-up asking for confirmation:

Interact with Aave Protocol

And there we go! We have deposited 0.1 ETH.

Interact with Aave Protocol

You can activate and deactivate the collateral option, you can also withdraw the money any time you want, and if you balance you will notice that the amount increases little by little.

Interact with Aave Protocol

You can also borrow any other assets that you want. To do that, you should click borrow next to the token that you want to borrow and choose the borrow APY rate and check the health factor to avoid being liquidated.

Interact with Aave Protocol

Click borrow DAI (the token we have chosen to borrow) and confirm the Metamask pop-up.

Aave Protocol

Now, you can see the borrows and supplies (deposits) lists on top.

Aave Protocol

You can repay DAI whenever you want. To do that, click repay:

Aave Protocol

Notice that even if you choose the max amount, you cannot repay all of it because the amount of debt has increased with time because of APY. Click approve to continue and confirm the Metamask pop-up.

Aave Protocol

After it is successfully done, you will be able to see that your debt has decreased to a very small fraction of DAI.

Aave Protocol

In the next part, we are going to interact with these tools through python scripts.

Last Thought

In this tutorial, we have managed to connect our Metamask to the Aave website to be able to interact with the Aave protocol directly. Then, we switched to Testnet. We also got some Kovan ETH from the Chainlink Kovan faucet. Using the test ETH we have got, we have managed to deposit it, withdraw Dai, and pay it back.

Download this Article in PDF format

metaverse

We Are Working on Metaverses

Metaverses, 3d modeling, 3d application, 3d websites, and even animations are just some of our vase expertise.

Arashtad Serivces
Tell us about your ideas
Fill in the Form
Blockchain Development

Getting Started with Smart Contracts Using Solidity: A Helpful Intro

This article aims to introduce Solidity language as a tool to write smart contracts and for the ease of the audience, it begins with Remix IDE to write the Solidity scripts. In this article, we are going to see how data types are defined in Solidity and learn how to work with Remix IDE. In addition to that, we are going to write smart contracts using Solidity to store and retrieve data.

Why Using Solidity?

One of the most famous languages used to deploy smart contracts on the Ethereum blockchain is Solidity. Once you learn how to code with this language, not only will you be able to write smart contracts, but you are open to many projects and tasks such as ICOs, NFT, metaverse, and so on. So learning how to write smart contracts using Solidity is the key to opening many doors to the hot topics of the world of blockchain and cryptocurrency.

Solidity is a high-level language that is influenced by C++, Python, and Javascript. It is object-oriented, supports inheritance, and is mostly designed to govern smart contracts and EVM (Ethereum Virtual Machine).

Solidity

Smart Contracts Using Solidity: Learning the Basics

Before getting started, you need to have a basic understanding of different concepts in blockchain, smart contracts, and the Ethereum network. In this tutorial, we have provided the definitions of some of the useful terms and a number of main concepts about the Ethereum network that we are going to work with throughout the course. But don’t worry, most of these terms and concepts are explained in between the practical codes so that you can have a deeper understanding of smart contracts using Solidity.

Getting started with Remix IDE

We begin our first simple smart contract with a storage example. Before we go after the scripts, we should determine what text editor we are going to use. For beginners, we recommend using remix IDE. For further uses where we want to run more advanced projects that need to be run next to python or node.js, you can use sublime text or other text editors but keep in mind that if you want to run Solidity script outside remix, you will need to install it on your terminal or command prompt. The files are also saved in the .sol format. So, with that being said let’s code our very first Solidity smart contract in remix:

Once you head over to remix IDE on your browser, you will see different featured plugins, one of which is Solidity. Click on it.

smart contracts using solidity

On the navbar of the left-hand side, you will see some icons. Click on the Ethereum icon, and you will see that you are given an Ethereum account on a test network to deploy and test your smart contracts. Besides, it has a certain balance to support the gas fees of every transaction.

smart contracts using solidity

Now, switch to file explorer where you can manage your script files. Click on the contracts folder and create a new file, then save the name of the file as FirstContract.sol.

smart contracts using solidity

If you select the Solidity icon on the navbar, you will be able to see the version of the compiler which shows different versions of Solidity. Notice that the Solidity version number is in the format of 0.x.y. So, as mentioned in the Solidity documentation, if the code version of Solidity is 0.x.y, it should be complied with 0.x.z where z>y. In other words, the version of the Solidity compiler should be greater than the version of the code. (In the code, you will see that we use pragma Solidity 0.x.y, that is the of Solidity).

smart contracts using solidity

The First Solidity Script

Now that we are familiar with the remix IDE, Let’s write our first script:


pragma Solidity >= 0.4.16 < 0.9.0;

contract SimpleStorage {
	uint storedData;
	function save(uint _storedData) public {
		storedData = _storedData;
	}

	function retrieve() public view returns (uint) {
		return storedData;
	}
}


As you can see, we have specified the version of Solidity to be somewhere between 0.4.16 and 0.9.0 not to face any further issues. Of course, if you install Solidity on your operating system, you will need to specify it according to the version you have installed. Now, it’s time to define our contract, SimpleStorage, and then define our variable storedData. In Solidity we have 2 specifiers for variables, one that defines the data type (like uint, uint 256, uint8, bool, string, address, byte, string, and so on) and the other that specifies the visibility of the variable.

Visibility of the Variables

There are 4 types of specifiers dealing with the visibility of the variables:

    1. internal:

Every function or variable if not specified, will be defined as internal by default. When it is specified this way, it will only be visible inside the function and nowhere else, unless it is retrieved by a view or pure function, which we will talk about later.

    2. external:

It can be used outside the function.

    3. private:

It's the same as internal but with the more restricted privacy of visibility.

    4. public:

It can be fetched anywhere and works as a global variable or function.

In the above code, because we haven’t specified the visibility of the storedData variable, it is by default internal. Notice that we have also specified the visibility of the functions inside the smart contract. Finally, we have defined a function named retrieve and because we have written view before returns, it can gain access to any internal variable outside the function and return it. Without a view, we won’t be able to gain access to storedData variable unless it was declared as public.

If we compile this code, in the Deploy and run (Ethereum icon) section and click deploy, in the deployed contracts part, we will be able to see 2 buttons, save and retrieve. Which is representative of the 2 functions we have defined.

After deploying the contract you will see that a small proportion of your balance has been subtracted from the cost of the transaction.

smart contracts using solidity

If you enter a number in the blank form next to save and press it and then press retrieve, you will be able to see the number you had entered, appears under the retrieve button.

smart contracts using solidity

Congratulations! You have successfully deployed your first smart contract. In the next sections of our tutorials, we are going to write more complex smart contracts and get closer to the real world Decentralized applications.

Smart Contracts Using Solidity: Structs

So far, we’ve learned how to store and save data in Solidity. But, what if we want to have different items or people with their associated numbers stored? We need a new type of function to do that for us. It is most similar to a class in python or other languages.

Struct works nearly the same as the class in other object-oriented languages. In the below example we are going to define a struct named employees and store their data such as their salary next to their names.


pragma solidity >= 0.4.16 < 0.9.0;
contract SimpleStorage {
          struct employees{
                    uint256 salary;
                    string name;
          }
          employees public person = employees({salary: 4000, name: "Harry"});
}

smart contracts using solidity

As you can see, once we deploy the contract, a new button appears called the person. And, if you click on it, you will be able to see the name and the salary of the employee that you added to the struct. Notice that since we have specified the type of the variable (person) as public, we can see the button person appears after deploying the contract. Now, if instead of a person, we want to enter a group of people, we use array.

So instead of writing:


employees public person = employees({salary: 4000, name: "Harry"});


We write:


employees [] public person;
function addEmployee( uint256 _salary, string memory _name) public {
	person.push(employees(_salary,_name));
}


We can add as many employees as we want to the list of employees. The employees [] public person array is a dynamic array. If we want the array size to be a fixed number. We can write employees [fixed_number] public person in which the fixed_number is an integer. After deploying the above code, we will see that 2 buttons appear:

smart contracts using solidity

If we enter (2500,”Harry” ) next to the addEmployee button and press it, then next to the person we will write the index of the member of the array which is 0 here. If we click the person button, we will see that the salary of 2500 and the name “Harry” appears under the person button.

smart contracts using solidity

Notice that in the addEmployee function, we have declared the name type as memory. There are 2 ways to store data in Solidity, memory, and storage. If we declare it as memory, it will only be stored during the execution time and then it will be removed. But if we declare it as storage, it will be saved permanently.

Now, we have another problem. If for example, we want to fetch the salary of “Harry” or someone else, we cannot do that. This is the place where we use mapping.

Mapping in Solidity

Mapping is a kind of data structure that allows you to map a certain part of your data to be connected to its related features.

Now, if apply this mapping to our code:


mapping (string => uint256) public SalaryOfEmployee;


And also in our addEmployee function we write:


SalaryOfEmployee[_name] = _salary;


We will be able to fetch the salary of every person we add to the list of employees.

smart contracts using solidity

Congrats! Now we can store data like a database using Solidity if instead of memory we write storage in addEmployee function.

Connecting Remix IDE to Metamask

To get closer to real-world smart contracts, we should run our code using a testnet or mainnet. To do that, we can install Metamask and use the Rinkeby testnet.

First off, install Metamask extension on your browser using this link and while opening your wallet account, do not forget to write down the mnemonic keywords somewhere on paper.

smart contracts using solidity

Once you entered your wallet in the browser extension, go to settings:

smart contracts using solidity

And in the advanced settings turn on the show test networks:

smart contracts using solidity

Now, you will be able to switch to the Rinkeby test network:

smart contracts using solidity

To get some Ethereum for the gas fees of our smart contract, we can go to this link (https://faucet.rinkeby.io/) tweet or facebook the phrase it gives you.

smart contracts using solidity

Now you should copy and replace the address of your account with 0x000000… .

smart contracts using solidity

Copy the link of the tweet next to “give me Ether” and press the button. Then, select any of the amount of Ethereum you want and press it. Now if you check your Rinkeby network account, you will be able to see that it has your selected amount of Ethereum.

smart contracts using solidity

Now, it is time to connect Remix IDE to your Metamask wallet. To do that, you need to change the environment from JavaScript VM to injected Web3. Once you do that, the Metamask extension will pop up asking whether you want to connect Metamask to connect to remix IDE. Click next, and then connect. Now, you can see that your Metamask is connected to remix IDE. Now if you check the account under the environment in Remix IDE, you will be able to see that instead of 100 ETH you have 18.75 ETH which is related to your Metamask test network balance.

smart contracts using solidity

Now, we have successfully connected our IDE to Metamask and can continue our adventure in the world of smart contracts using more real-world tools.

Smart Contracts Using Solidity: Connecting to Testnet

In the previous sections, we learned how to connect remix IDE to the Metamask wallet. Moreover, we learned how to get some free Ethereum for our testnet which was Rinkeby. Now if we deploy our contract, you will see that metamaks pops up and asks you to confirm the transaction and the required gas fee for it. Press Confirm and then you will see that the balance of your account decreases from 18.75 to 18.7489 ETH. Now you can test your smart contract, this time using the Rinkeby test network.

solidity

Using Etherscan

Notice that once we deploy our contract, we get a link of Etherscan in the console section of the IDE to be able to track our transaction on the Ethereum blockchain.

solidity

It is also worth mentioning that when we deploy the contract and store data, for example ( here we have addEmployee) again we will face the Metamask pop-up that asks us whether we want to confirm the transaction or not. Notice that every storage is considered as a transaction on the Ethereum blockchain and is trackable using the Etherscan link given on the console.

solidity

However, the retrieve functions when applied will not cost anything, because they are not considered a transaction. In the photo below you can see that we have retrieved the specifications of the first member of the list and also Sarah’s salary, it hasn’t ended up with the Metamask pop-up asking for any kind of confirmation.

solidity

Up to now, we have learned how to write and deploy a smart contract. But what if we want to deploy a contract using another contract?

How to deploy a contract from another contract?

At first, we make a new project in our current folder (=>contracts => artifacts) and call it storageBank.sol. Then, write the following code in the new file you’ve just created.


// SPDX-License-Identifier: MIT

pragma solidity >= 0.4.16 < 0.9.0;

import "./FirstProj.sol";

contract StorageBank {
	SimpleStorage[] public StorageArray;
	function StorageContract() public{
		SimpleStorage storageContract = new SimpleStorage();
		StorageArray.push(storageContract);
	}
}


// SPDX-License-Identifier: MIT is the necessary part of every Solidity script file that shows the license of the Solidity and helps you avoid the license warning. The first thing that you will notice when reading this script is that we have imported our last script file and that is the contract that we want to deploy in this new contract.

So, we define a new contract called StorageBank and inside of it, we declare an array called StorageArray with SimpleStorage identifier and public declaration. Then, we define a public function called StorageContract using which we call the recent contract that we had imported in this one and put it in the StorageArray.

Once we deploy this contract, we will again see the Metamask pop-up and after a few seconds, we can open the contract and press StorageContract. The same popup scenario repeats for this one as well and then shortly after, when the transaction has been confirmed by Metamask, we will be able to retrieve and run FirstProj.sol contract. To do that, we enter 0 in the box next to StorageArray and press the key. Once you do that, you will see the address of the contract you’ve been willing to open from this one appears below the button.

solidity

Now, without using any of the functions inside FirstProj.sol contract, the above code is useless. So, now using the script below in the following instead of the previous code, we will be able to use our desired functions.


// SPDX-License-Identifier: MIT
pragma solidity >=0.4.16 <0.9.0;

import "./FirstProj.sol";

contract StorageBank {
	SimpleStorage[] public StorageArray;
	function createStorageContract() public{
		SimpleStorage simplestorage = new SimpleStorage();
		StorageArray.push(simplestorage);
	}

	function SaveNumber(uint256 _storeIndex, uint256 _storageNumber) public{
		SimpleStorage simplestorage = SimpleStorage(address(StorageArray[_storeIndex]));
		simplestorage.store(_storageNumber);
	}
}


Notice that here we are calling the function that we used to save and retrieve a number from another contract, not the one that we would retrieve the salary of an employee.

By running and deploying the above code we will be able to save a number inside the contract with index 0 and then save another number with the next index number and so on. The index shows the number of times that we use a specific contract and applies it multiple times.


function GetNumber(uint256 _storeIndex) public view returns(uint256){
	SimpleStorage simplestorage = SimpleStorage(address(StorageArray[_storeIndex]));
	simplestorage.retrieve();
	

Adding the above code to the rest of the contract will return the number that we have saved. That’s it! now we can have interaction between different contracts or in other words we can inherit from a contract and use it in another one.

Last Thought on Solidity

In this article, we have got familiar with Solidity language for developing smart contracts on the Ethereum blockchain. Moreover, we usded the Remix IDE as a simple-to-use IDE to get started with writing smart contracts on the Ethereum blockchain. In addition to that, we have written a very simple smart contract to store a variable and retrieve it whenever we want. This kind of contract is commonly known as a simpleStorage smart contract.

Furthermore, we have learned about the use cases of mapping and struct in Solidity by using them inside a smart contract. We have also managed to connect our Remix IDE to the Metamask to be able to pay for the cost of our transaction gas fees with this wallet. Besides, we needed some ETH, which we got from Rinkeby Testnet Faucet.

In the end, we have managed to execute our smart contract transactions on the Rinkeby Testnet with the aid of the Metamask wallet. It led to asking for confirmation of the transactions and paying the fees of every transaction. As well as that, We tracked our transaction using Etherscan. We have also managed to deploy a contract using another contract.

Download this Article in PDF format

3d animation

Check Out Our Services

In Arashtad, we're working on 3D games, metaverses, and other types of WebGL and 3D applications with our 3D web development team.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Request a Quote
ThreeJS Development