How to Deploy and Interact with Solidity Contracts with Python and Ganache

Muhammed Ali
CoinsBench
Published in
6 min readMay 5, 2022

--

Introduction

Do you know you can use solidity with Python? Do you know it is possible to deploy your Solidity smart contract with Python?

If these questions have come to your mind, then you have come to the right place. In this tutorial, I will show you how you can go about deploying your Solidity contract with Python and also how to interact with the contract. We will, first, build a simple Solidity contract before deploying it with Python and then interacting with it.

While working with Solidity locally, you may want to test out and interact with your smart contract, you can use a tool called Web3.py.

Prerequisites

  • Basic understanding of Python
  • Basic understanding of Solidity and Ethereum Blockchain

Developing a Simple Solidity Contract

We will be building a contract that stores users and their phone numbers, i.e. a contact list contract. This is not idealistic, but we just need something we can use to test out our deployment.

To accomplish this, we just need to initialize an array of contact names and phone numbers, map them together, append the contact to the contact array then write a statement to enable us to get the phone number from the contact name.

To get started, create a new Solidity file for your project, in my case, it’ll be ContactList.sol. Now paste the code below in the file you just created. I have added comments to describe what each line is doing.

// SPDX-License-Identifier: MITpragma solidity 0.8.0;contract ContactList {    // uint phoneNumber;
uint256 phoneNumber;
struct Contact {
// assosiate name with phone number
string name;
string phoneNumber;

}
Contact[] public contact; //array for list of contacts
mapping(string => string) public nameToPhoneNumber; //used to map name to phone number, so you can get phone number using name

function retrieve() public view returns (Contact[] memory){
return contact; //retrieve tuple of all contacts
}

function addContact(string memory _name, string memory _phoneNumber) public {
contact.push(Contact(_name, _phoneNumber)); //append to Contact[] array
nameToPhoneNumber[_name] = _phoneNumber; //use name to get phone number
}

}

You can test out the contract on Remix to see if it is working as it is supposed to before going further in the process.

Deploying Solidity Smart Contract with Python

Now we are in the Python section of this article. For deployment, what we can do is read the Solidity file, compile it, change the contract to Python, build the contract, sign the contract and send the contract.

To start, create a new Python file in the same directory you have the Solidity file (deployment.py). Next, paste the following code to read the Solidity file.

with open("ContactList.sol", "r") as file:
contact_list_file = file.read()

Now we have to compile the Solidity code with just read. We will do that with py-solc-x. First install the library by running pip install py-solc-x. From py-solc-x we need the compile_standard() and install_solc() methods for the compilation. Import the methods by pasting from solcx import compile_standard, install_solc at the top of your Python file.

To compile with compile_standard(), you need to state some parameters, as you can see in the code below.

import json #to save the output in a JSON file
...
compiled_sol = compile_standard(
{
"language": "Solidity",
"sources": {"ContactList.sol": {"content": contact_list_file}},
"settings": {
"outputSelection": {
"*": {
"*": ["abi", "metadata", "evm.bytecode", "evm.bytecode.sourceMap"] # output needed to interact with and deploy contract
}
}
},
},
solc_version="0.8.0",
)
print(compiled_sol)
with open("compiled_code.json", "w") as file:
json.dump(compiled_sol, file)

Now run the code you have, and you notice that the output has been dumped in compiled_code.json. We need to traverse the JSON to get the ABI and bytecode so it will be helpful to go through the JSON output. To extract the ABI and bytecode paste the following code below the code that you have.

# get bytecode
bytecode = compiled_sol["contracts"]["ContactList.sol"]["ContactList"]["evm"]["bytecode"]["object"]
# get abi
abi = json.loads(compiled_sol["contracts"]["ContactList.sol"]["ContactList"]["metadata"])["output"]["abi"]

Using Ganache as Blockchain

To deploy our contract, we need a blockchain. Ganache CLI provides a simulated blockchain that you can use to test out things in deployment. To use Ganache, we need a tool to help us create our contract in Python, this is where Web3.py comes in.

You can install Web3.py by running, and you can check Ganache CLI package page to get instructions on how to install it.

We need a couple of things from Ganache in order to create the contract RPC Server, chain ID(1337 for Ganache), address, and private key. You can get the credentials by running ganache-cli --deterministic. Running the command will activate the server with the necessary credentials.

Now paste the following code into your deployment.py file. Compare the credentials in the code with the image above to see where things fit.

...
from web3 import Web3
...
# For connecting to ganache
w3 = Web3(Web3.HTTPProvider("<http://127.0.0.1:8545>"))
chain_id = 1337
address = "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
private_key = "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d" # leaving the private key like this is very insecure if you are working on real world project
# Create the contract in Python
ContactList = w3.eth.contract(abi=abi, bytecode=bytecode)
# Get the number of latest transaction
nonce = w3.eth.getTransactionCount(address)

Now, to complete the deployment we have to build, sign and send transactions (change of state of a blockchain) to Ganache. To do this, paste the following code into your deployment.py file.

Note: Ganache is the tool with ganache CLI is the command-line interface for Ganache

# build transaction
transaction = ContactList.constructor().buildTransaction(
{
"chainId": chain_id,
"gasPrice": w3.eth.gas_price,
"from": address,
"nonce": nonce,
}
)
# Sign the transaction
sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=private_key)
print("Deploying Contract!")
# Send the transaction
transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
# Wait for the transaction to be mined, and get the transaction receipt
print("Waiting for transaction to finish...")
transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")

Now that we have set everything, you can now deploy your contract by running your Python code. Make sure your Ganache server is still up, otherwise it won’t work.

Go to your Ganache server and you will see that we have deployed a transaction, and we have created the contract.

Interacting with the Contract

Two ways to interact with a contract with call() (calls a function and gets return value) and transact() (make changes in the contract).

When trying to interact with a contract, you need the contract address and the contract ABI. We got the ABI earlier, but we can get the contract address for the transaction_receipt as you will see in the code below. Add the following code below what you have in your deployment.py file to initialize our contract with the contract address and ABI.

contact_list = w3.eth.contract(address=transaction_receipt.contractAddress, abi=abi)

You can now create a contract by pasting the code below, in the code below you are just adding a contact.

store_contact = contact_list.functions.addContact(
"name", "+2348112398610"
).buildTransaction({"chainId": chain_id, "from": address, "gasPrice": w3.eth.gas_price, "nonce": nonce + 1})

Now sign, send and wait for the transaction to finish.

# Sign the transaction
sign_store_contact = w3.eth.account.sign_transaction(
store_contact, private_key=private_key
)
# Send the transaction
send_store_contact = w3.eth.send_raw_transaction(sign_store_contact.rawTransaction)
transaction_receipt = w3.eth.wait_for_transaction_receipt(send_store_contact)

Now you can retrieve the contract with the call() function.

print(contact_list.functions.retrieve().call())

Now run the code with python3 deployment.py, and you will see something like the image below. This shows that we have successfully saved the contact, and we can retrieve the contact.

Conclusion

In this tutorial, we were able to build a simple Contract in Solidity, and get the necessary data required to build the contract in Python using py-solx. We then went further to convert the Solidity contract into Python and then built, signed, and sent the transaction to Ganache using Web3.py.

Ganache is not an actual blockchain, so please don’t put real money in it, we are just using it to test things out locally.

You can find the code for this tutorial on GitHub.

--

--

Technical Writer with experience in building awesome stuff with Django, Python, JavaScript, React, Kubernetes, etc. || Cloud-Native enthusiast.