Web3 DApp Full Scale Development Using Python and Brownie – Lottery

This article shares how to develop a Web3 DApp using Python, Brownie, Solidity, and other assistant software. This application basically can use Crypto to play a lucky draw through blockchain networks. It’s like any lucky draw game where the host can set up a lottery game and the players who pay for it and join, can randomly win a prize or not.

web3 dapp

This article shares how to develop a Web3 DApp using Python, Brownie, Solidity, and other assistant software. This application basically can use Crypto to play a lucky draw through blockchain networks. It’s like any lucky draw game where the host can set up a lottery game and the players who pay for it and join, can randomly win a prize or not.

Ingredients on Web3 DApp Full Scale Development

Python, Brownie, Solidity, Openzeppelink, Ethereum, Ganache-CLI, MetaMask, Alchemy, Chainlink, Etherscan

Table of Contents on the sample of a Lottery Application

Develop a Smart Contract Using Solidity and Chainlink

Here is the main flow in the Lottery DApp integrated with multi-networks as follows:

  • Users can enter lottery fund
  • The lottery starts and ends automatically
  • The application can randomly select a winner

There are a few imperative parts to share in terms of this DApp development logic in the smart contract.

1. Create a lottery logical flow in a solidity smart contract by adding functions

In a lottery smart contract, the playing journey basically at least includes 

  • Currency amount enter
  • Get the transaction fee
  • Start the lottery
  • End the lottery
  • Fulfill Randomness Function

web3 dapp

2. Test the lottery smart contract function by creating a mainnet-fork env and a testing script.

Before talking about point 2, please be sure to notice pragma 0.8 which msg.sender is not automatically payable any more. So you need to make it payable first like this:

players.push(payable(msg.sender));

To add testing mainnet-fork network in the local environment, here we use Alchemy as the host

Just input this list of commands in the terminal:

brownie networks add development mainnet-fork cmd=ganache-cli host=http://127.0.0.1 fork=https://eth-mainnet.g.alchemy.com/v2/abcabc accounts=10 mnemonic=brownie port=8545

Take the getEntraceFee function for example. Here is the test result by running the brownie test –network mainnet-fork

For the testing script, please subscribe to our Easy2Digital newsletter by leaving a message “Web3.0 DApp full script tutorial 5”, which we’ll send you soon.

3. Add ENUM Statement

For a lottery, we need to set up three scenarios, which are the lottery open, closed, and calculating the winner. Here is the code as follows:

 enum LOTTERY_STATE {

        OPEN,

        CLOSED,

        CALCULATING_WINNER

    }

    LOTTERY_STATE public lottery_state;

Then, for any lottery start, we require only owners who can make a call rather than any game players are entitled to do it. For this, we can import a smart contract owner sol using open zeppelin.

import "@openzeppelin/contracts/access/Ownable.sol";

    function startLottery() public onlyOwner {

        require(lottery_state == LOTTERY_STATE.CLOSED, "Can't start a new lottery yet!")

        lottery_state = LOTTERY_STATE.OPEN;

    };

And the brownie-config.yaml, please be sure to use the latest open zeppelin version. For example, mine is 4.8.0

- OpenZeppelin/openzeppelin-contracts@4.8.0

4. Randomness

After the lottery has started, it’s necessary to generate an outcome randomly. Thus, we need a random number package to fulfill this function and deliver the result.

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";

Based on the randomness functions and parameters, we need to refer to them and deploy them in the smart contract. Below are the places to be updated as follows:

Contract –> to add VRFConsumerBase in the lottery function

In the contract, we need to add some global variables as follows:

    address payable[] public players;

    address payable public recentWinner;

    uint256 public randomness;

    uint256 public fee;

    bytes32 public keyhash;

Constructor → to add as follows:

contract Lottery is VRFConsumerBase, Ownable {

    address payable[] public players;

    address payable public recentWinner;

    uint256 public randomness;

    uint256 public usdEntryFee;

    AggregatorV3Interface internal ethUsdPriceFeed;

    enum LOTTERY_STATE {

        OPEN,

        CLOSED,

        CALCULATING_WINNER

    }

    LOTTERY_STATE public lottery_state;

    uint256 public fee;

    bytes32 public keyhash;

    constructor(

        address _priceFeedAddress,

        address _vrfCoordinator,

        address _link,

        uint256 _fee,

        bytes32 _keyhash

    ) public VRFConsumerBase(_vrfCoordinator, _link) {

        usdEntryFee = 50 * (10**18);

        ethUsdPriceFeed = AggregatorV3Interface(_priceFeedAddress);

        lottery_state = LOTTERY_STATE.CLOSED;

        fee = _fee;

        keyhash = _keyhash;

    }

Compiled!!

Main Deployment and Assistant Python Scripts in Lottery Application

There are a few core Python scripts to deploy in this Lottery application. Here are the details as follows:

1. Main script, such as deploy_lottery.py on element selections of accounts, network, wallets, and so on and so forth.

1) Account Identifier and Grabber

In a real lottery game, people might use different types of accounts to join and play. So main script must be able to detect the account users are using, which includes the network. Here is the code sample as follows: 

def deploy_lottery():

    account = get_account(id="easy2digitalAccount")

2) Contract, Networks, Wallet Identifier and Grabber

   lottery = Lottery.deploy(

       get_contract("eth_usd_price_feed").address,

       get_contract("vrf_coordinator").address,

       get_contract("link_token").address,

       config["networks"][network.show_active()]["fee"],

       config["networks"][network.show_active()]["keyhash"],

       {"from": account},

       publish_source=config["networks"][network.show_active()].get(

           "verify", False),

   )

3) Functions on Lottery Start, Fee Entry, and End

Excerpt for the deployment function, it’s also necessary to have start, entry, and end functions in the Python script which works with the Lottery smart contract.

  • start_lottery()
  • enter_lottery()
  • end_lottery()

Take the start_lottery() for the example

def start_lottery():

   account = get_account()

   lottery = Lottery[-1]

   starting_tx = lottery.startLottery({"from": account})

   starting_tx.wait(1)

   print("The lottery has started!!")

2. scriptAssistant.py

Regarding this assistant python file, it’s used to support the Python deployment script execution. We import them at the beginning of the deployment script:

from scripts.scriptAssistant import get_account, get_contract, fund_with_link
Here are the four main functions in the assistant script
  • get_account()
  • get_contract()
  • deploy_mocks()
  • fund_with_links()

Take the Get_account function for example

def get_account(index=None, id=None):

    if index:

        return accounts[index]

    if id:

        return accounts.load(id)

    if (

        network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS or network.show_active(

        ) in FORKED_LOCAL_ENVIRONMENTS

    ):

        return accounts[0]

Add Mock, VRF, and Link Token Test contracts

Based on the smart contract constructor for building up a Lottery application, we need some external resources to integrate with our application. In this article, we take Chainlink as the resource sample. Below are the 5 components we need as follows:

  • Price Feed Address
  • VRF Coordinator
  • Link Token
  • Key Hash
  • Fees

We need to go to Chainlink GitHub to copy the latest version and paste it to our contracts folder separately. The sample is as follows:

web3 dapp

For the price feed address, link token key, key hash, and fee, please go to Chainlink’s official website and look up the related information.

Rest of the Critical Components – config YAML and env

The rest of the key components are the brownie config YAML file and the env file. For more details, please check out the previous article regarding the fund-me smart contract. Basically, the setting is the same as the lottery application now we’re talking

Brownie FundMe Smart Contract Deployed on Ethereum Using Python & Web3

Unit Testing

As mentioned in the previous articles, one of the most powerful functions given by Brownie is the testing environment. Without a doubt, we are not willing to kick the application off before having confirmed things are ready. So testing is a must step whatever DApp you are developing.

In terms of the testing components, basically, we need to follow the smart contract steps and test them one by one. Here are the 5 steps as follows:

  • test_get_entrance_fee()
  • test_cant_enter_unless_starter()
  • test_can_enter_unless_starter()
  • test_can_end_lottery()
  • test_can_pick_winner_correctly()

Take the test_get_entrance_fee() for example

def test_get_entrance_fee():
if network.show_active() notinLOCAL_BLOCKCHAIN_ENVIRONMENTS:
pytest.skip()
# Arrange
lottery = deploy_lottery()
# Act
expected_entrance_fee = Web3.toWei(0.025, "ether")
entrance_fee = lottery.getEntranceFee()
# Assert
assertexpected_entrance_fee == entrance_fee

Connect the Authentic Network and Make it Live

Once the testing is done and things all go well, it’s time to connect the real network and kick it off! For more details, please check out the previous article regarding use the Infura and MetaMask to deploy on Ethereum.

Full Python and Solidity Script of Web3 DApp Full Scale – Lottery Application

If you are interested in the full set of scripts of Web3 DApp Lottery, please subscribe to our newsletter by adding the message “Web3.0 tutorial 5”. We would send you the script immediately to your mailbox.

I hope you enjoy reading Web3 DApp Full Scale Development Using Python and Brownie – Lottery. If you did, please support us by doing one of the things listed below, because it always helps out our channel.

Leave a Reply

Your email address will not be published. Required fields are marked *