How To Deploy A Smart Contract On Blockchain Using Python
Tags: blockchain, web3, solidity, python
Published: 2022-05-23 16:41:09

## Dependencies  
  
**Python** 
 
__*web3.py :*__
Web3.py is a Python library for interacting with Ethereum.  

It’s commonly found in decentralized apps (dapp) to help with sending transactions, interacting with smart contracts, reading block data, and a variety of other use cases.  

> Installation:  
> ```terminal
> pip install web3
> ```

__*Py-solc-x | Py-solc :*__

Py-solc is a Python wrapper and version management tool for the solc Solidity compiler

> Installation:
> ```bash
> pip install py-solc-x
> ```

---

**Ganache UI | Cli**
> Installation:
> - **Ganache Desktop**   
> [Download Link](https://trufflesuite.com/ganache/)
> ![Ganache UI download website](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0ajsb3yb2nm8zi0y4bz.png)
> <hr>
> <center> __OR__ </center>
> - **Ganache-cli** : `pip install ganache-cli`


## Lets Get Started  

**1.** Open the directory where you have put your smart contract in the code editor like VSCode.  

**2.** Create solidity file `SmartContractDemo.sol`.
```solidity
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

contract SmartContractDemo {
    struct Person {
        string name;
        string dateOfBirth;
    }

    Person[] public idCard;

    function numberOfEntries() public view returns (uint256) {
        return idCard.length;
    }

    function store(string memory _name, string memory _birthday) public {
        idCard.push(Person(_name, _birthday));
    }

    function changeData(
        uint256 index,
        string memory _name,
        string memory _birthday
    ) public {
        require(index <= numberOfEntries(), "Given index not present");
        idCard[index] = Person(_name, _birthday);
    }

    function retrieve(uint256 index)
        public
        view
        returns (string memory, string memory)
    {
        require(index <= numberOfEntries(), "Given index not present");
        return (idCard[index].name, idCard[index].dateOfBirth);
    }
}
```
 
**3.** Next create a python file `deploy.py`. Here, we write the code required to push our contract to the blockchain.  

**4.** First add the below code to import the web3 and py-solc-x in python files:  
 
```python
from web3 import Web3
from solcx import compile_standard, install_solc

import json
``` 

**5.** Read and store the content of SmartContractDemo.sol in a separate variable:  

```python
# extract the content of SmartContractDemo.sol
with open("./SmartContractDemo.sol", "r") as file:
    smart_contract_demo = file.read()
```

**6.** Run the below code to install solc and compile the solidity code:   

```python
install_solc("0.6.0")

# Solidity source code
compiled_sol = compile_standard(
    {
        "language": "Solidity",
        "sources": {"SmartContractDemo.sol" : { "content" : smart_contract_demo_file }},
        "settings": {
            "outputSelection": {
                "*": {
                    "*": ["abi","metadata","evm.bytecode","evm.sourceMap"]
                }
            }
        }
    },
    solc_version="0.6.0",
)
```

**7.** The below code will put in the compiled_code as a new JSON file.  

```python
with open("compiled_code.json","w") as file:
    json.dump(compiled_sol,file)
```

**8.** Now before we deploy this contract, we need **abi** and **bytecode** first which we can get from compiled_code. This can be achieved by using this code:  
 
```python
# get abi
abi = compiled_sol["contracts"]["SmartContractDemo.sol"]["SmartContractDemo"]["abi"]

# bytecode
bytecode = compiled_sol["contracts"]["SmartContractDemo.sol"]["SmartContractDemo"]["evm"]["bytecode"]["object]
```

**9.** Connecting to Ganache:   
To connect with ganache, we need an HTTP Provider URL, chain-id, the public key & private key which will be going to be used for deploying our smart contract.

_How to  get HTTP provider, chain-id, the public and private key of Transaction account_:    
**If you are using Ganache UI**   
Step 1: Open Ganache App.   
Step 2: Click on the Quickstart button.  
![Ganche-ui starting page](https://cdn.hashnode.com/res/hashnode/image/upload/v1653219298305/j5c2PnhlU.png)
 
   
![ganche-cli overview.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1653239135747/fW2UMcrUo.jpg)  
This is what Ganache-UI looks like were  
- **White**-outlined box give us the **RPC server** i.e., `http://127.0.0.1:7545`  
- **Yellow**-outlined box give us **chain_id** i.e, `5777`  
- **Red**-outlined box marks the public key of the account e.g., `0xE1584b4d8f1b0CeEF97190B296DaF446674A3d63`
- **Blue**-outlined box point to the button will show the private key associated with the given account   

*or*

**If you are using Ganache-CLI**  
Step 1: Open a terminal and then run the given command: `ganache-cli`.   
This will launch the ganache-cli terminal. 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653242527813/JDwN-Y3mB.png align="left")    
  
Step 2: Copy and note the public key and private key associated with any account, clain-id, and RPC server url which is `http://127.0.0.1:8545` in my case.   


### Important Note:  
- Accounts provided in the Ganache are only meant for development and testing purposes. Please, don't try to do actual transactions.  
- **Private keys** are highly confidential. So, keep your private keys safe. It allows the user to access the wallet.    

**10.** Managing private key  
__Adding private key:__  
Even if we are just using the private key associated with ganache, for best practice we should always avoid hard coding private key in our coding.  
So, to store the private key, we will add it as an environment variable and extract it in our python program `deploy.py` using **OS module**.  
  
To do so :  
- Inside same directory, add a file `.env`  
- Open `.env` file and write: `export $PRIVATE_KEY=<put your private key here>`
  e.g.,  
![[Pasted image 20220523145104.png]]
- Head back to `deploy.py` and import these module at the top:  
![[Pasted image 20220523145413.png]]
  
**11.**  Go back to our `deploy.py` and connect it with ganache.   
```python
# Connecting to ganache
w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))
chain_id = 5777
my_address= "0xE1584b4d8f1b0CeEF97190B296DaF446674A3d63"
private_key = os.getenv("PRIVATE_KEY")
```   
   
**12.** Now let's create the contract in python and get the latest transaction. 
```python
# Creating contract in python
SmartContractDemo = w3.eth.contract(abi=abi, bytecode=bytecode)

# Get the latest transaction
transaction = SmartContractDemo.constructor().buildTransaction({
    "chainId": chain_id,
    "gasPrice": w3.eth.gas_price,
    "from": my_address,
    "nonce": nonce,
})
```

**13.** Finally, let's sign our transaction and deploy it.  
```python
# Sign the transaction
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key)

print("Deploying Contract!")
# Sent it
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)

# Wait for the transaction to be mined, and get the transaction receipt
print("Waiting for Transaction to finish...")

tx_receipt=w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Done! Contract Deployed to {tx_receipt.contractAddress}")
```

Well done! We have successfully learned to deploy Smart Contract to the local blockchain.

## Interacting with our smart contract

There are two types of Interaction one can make with a Smart Contract: 
1. Call -> Simulate making the call and getting a return value
2. Transact -> Actually make a state change 

Let's perform both the interaction with our smart contract :

**1.** To call a public function `numberOfEnteries()`from SmartContractDemo, go back to `deploy.py`.  
```python
# Working with the contracts
smart_contract_demo = w3.eth.contract(address=tx_receipt.contractAddress, abi=abi)

print(f"Number of Enteries in idCard array is {smart_contract_demo.functions.numberOfEnteries()}")
```

**2.** Now a state change by adding a data to the `idCard` array using the function `store()`:
```python
store_transaction = smart_contract_demo.functions.store("Naruto", "10-10-1999").buildTransaction({
    "chainId": chain_id,
    "gasPrice": w3.eth.gas_price,
    "from":my_address,
    "nonce":nonce+1,
})

signed_store_txn = w3.eth.account.sign_transaction(
    store_transaction, private_key=private_key
)

signed_store_hash = w3.eth.send_raw_transaction(signed_store_txn.rawTransaction)

tx_receipt = w3.eth.wait_for_transaction_receipt(signed_store_hash)
```
  
Whenever we make a state change, the transaction has to be signed first with our private key.

> **Note:**
> Calling a view or pure public function doesn't cost anything.
> Whereas deploying a smart contract and making a function call that changes the state of the blockchain cost some amount of GAS Fees.

**3.** Finally, finish it by again calling `numberOfEnteries()` function and retrieve() function.  
```python
print(f"Number of Enteries in idCard array is {smart_contract_demo.functions.numberOfEnteries()}")

print(f"Person at 0th index in idCard array is {smart_contract_demo.functions.idCard(0)}")
```
**4.** Now run the `deploy.py` file (run via terminal: `python ./deploy.py`).  

### OUTPUT:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653304572841/XyQkjwczs.png)
Now, if we check the ganache-cli, we can find two transaction records there,
1. The First transaction is about contract creation.  
2. The Second transaction is made we call the store function to add Personal detail to idCard array.  

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1653304828568/epc5Rsj43n.png)
## Resource Link 

Project Link:
- GitHub: https://github.com/subrotokumar/SmartContractDemo

Documentation: 
- web3.py : https://web3py.readthedocs.io/en/stable/
- py-solc-x : https://solcx.readthedocs.io/en/latest/

### [CONNECT WITH ME](https://subrotokumar.bio.link)

I hope you have found this article helpful. Thank you for reading!