Subscribe to our free newsletter

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

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