Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: example web3py usage #2723

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tools/web3py-example/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
OPERATOR_PRIVATE_KEY=
RELAY_ENDPOINT=
1 change: 1 addition & 0 deletions tools/web3py-example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
53 changes: 53 additions & 0 deletions tools/web3py-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Web3py example
Example scripts for basic operations

### How to start
1. **Install Solidity Compiler (`solc`)**:
- Install `solc` by following the instructions in the [Solidity documentation](https://docs.soliditylang.org/en/latest/installing-solidity.html).
- On Ubuntu, you can run:
```sh
sudo apt install solc
acuarica marked this conversation as resolved.
Show resolved Hide resolved
```

2. **Set up a clean environment (with virtual env)**

```bash
# Install pip if it is not available:
$ which pip || curl https://bootstrap.pypa.io/get-pip.py | python

# Install virtualenv if it is not available:
$ which virtualenv || pip install --upgrade virtualenv

# *If* the above command displays an error, you can try installing as root:
$ sudo pip install virtualenv

# Create a virtual environment:
$ virtualenv -p python3 ~/.venv-py3

# Activate your new virtual environment:
$ source ~/.venv-py3/bin/activate

# With virtualenv active, make sure you have the latest packaging tools
$ pip install --upgrade pip setuptools

# Now we can install web3.py...
$ pip install --upgrade web3

# Install python-dotenv
$ pip install python-dotenv

# Install py-solc-x
$ pip install py-solc-x
```

Remember that each new terminal session requires you to reactivate your virtualenv, like:
```bash
$ source ~/.venv-py3/bin/activate
```

3. **Create and complete `.env` file from `.env.example`**

4. **Run script**
```bash
python scripts/test.py
```
18 changes: 18 additions & 0 deletions tools/web3py-example/contract/Greeter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//SPDX-License-Identifier: Unlicense
mateuszm-arianelabs marked this conversation as resolved.
Show resolved Hide resolved
pragma solidity >0.5.0;

contract Greeter {
string public greeting;

constructor() public {
greeting = 'Hello';
}

function setGreeting(string memory _greeting) public {
greeting = _greeting;
}

function greet() view public returns (string memory) {
return greeting;
}
}
natanasow marked this conversation as resolved.
Show resolved Hide resolved
138 changes: 138 additions & 0 deletions tools/web3py-example/scripts/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#
# Hedera JSON RPC Relay - Web3py Example
mateuszm-arianelabs marked this conversation as resolved.
Show resolved Hide resolved
#
# Copyright (C) 2022-2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import unittest
from dotenv import load_dotenv
from web3 import Web3
from solcx import install_solc, compile_source

def setup_environment():
# install latest solc
install_solc(version='latest')
acuarica marked this conversation as resolved.
Show resolved Hide resolved

# load values from our .env file
load_dotenv()
OPERATOR_PRIVATE_KEY = os.getenv('OPERATOR_PRIVATE_KEY')
RELAY_ENDPOINT = os.getenv('RELAY_ENDPOINT')

# connect to chain
w3 = Web3(Web3.HTTPProvider(RELAY_ENDPOINT))

# get account from pk
acc = w3.eth.account.from_key(OPERATOR_PRIVATE_KEY)

return w3, acc


def get_balance(w3, acc):
acuarica marked this conversation as resolved.
Show resolved Hide resolved
balance = w3.eth.get_balance(acc.address)
return balance


def deploy_contract(w3, acc):
# read contract from file
with open('contract/Greeter.sol', 'r') as f:
source = f.read()

# compile our Greeter contract
compiled_sol = compile_source(source, output_values=['abi', 'bin'])
acuarica marked this conversation as resolved.
Show resolved Hide resolved

# retrieve the contract interface
contract_id, contract_interface = compiled_sol.popitem()

bytecode = contract_interface['bin']
abi = contract_interface['abi']

# create web3.py contract instance
Greeter = w3.eth.contract(abi=abi, bytecode=bytecode)

# build transaction
unsent_tx_hash = Greeter.constructor().build_transaction({
"from": acc.address,
"nonce": w3.eth.get_transaction_count(acc.address),
})

# sign transaction
signed_tx = w3.eth.account.sign_transaction(unsent_tx_hash, private_key=acc.key)

# send transaction
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)

# create instance of deployed contract
greeter = w3.eth.contract(
address=tx_receipt.contractAddress,
abi=abi
)

return greeter, tx_receipt.contractAddress


def contract_view_call(greeter):
greeting = greeter.functions.greet().call()
return greeting


def contract_call(w3, acc, greeter):
# build contract call transaction
unsent_call_tx_hash = greeter.functions.setGreeting('Hello2').build_transaction({
"from": acc.address,
"nonce": w3.eth.get_transaction_count(acc.address),
})

# sign transaction
signed_call_tx = w3.eth.account.sign_transaction(unsent_call_tx_hash, private_key=acc.key)

# send transaction
call_tx_hash = w3.eth.send_raw_transaction(signed_call_tx.rawTransaction)
w3.eth.wait_for_transaction_receipt(call_tx_hash)

# Verify the greeting has been updated
new_greeting = greeter.functions.greet().call()
return new_greeting


class TestGreeterContract(unittest.TestCase):

@classmethod
def setUpClass(cls):
cls.w3, cls.acc = setup_environment()
cls.greeter, cls.contract_address = deploy_contract(cls.w3, cls.acc)

def test_get_balance(self):
balance = get_balance(self.w3, self.acc)
self.assertIsInstance(balance, int, "Account balance is an integer")

def test_deploy_contract(self):
self.assertTrue(self.contract_address.startswith('0x'), "Contract address starts with '0x'")

def test_call_view(self):
greeting = contract_view_call(self.greeter)
self.assertEqual(greeting, 'Hello', "Initial greeting matches expected value")

def test_contract_call(self):
new_greeting = contract_call(self.w3, self.acc, self.greeter)
self.assertEqual(new_greeting, 'Hello2', "Updated greeting matches expected value")

final_greeting = contract_view_call(self.greeter)
self.assertEqual(final_greeting, 'Hello2', "Final greeting matches expected value after update")


if __name__ == "__main__":
unittest.main()
Loading