How to compile, deploy and interact with smart contracts using Apeworx(ape) and VS Code.
Tags: smartcontract, vyper, apeworx, web3
Published: 2024-06-01 11:34:44

Today, we are going to write our smart contracts using Vyper and the [Apeworx](https://docs.apeworx.io/ape/stable/userguides/quickstart.html) framework. We are going to connect to  the ethereum network using [Sepolia](https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.alchemy.com/faucets/ethereum-sepolia&ved=2ahUKEwjxiYmL67mGAxWk3QIHHTcoE8AQFnoECBUQAQ&usg=AOvVaw3SPRlvlGFEBx-iKOSKlCWU) via [Alchemy](https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.alchemy.com/&ved=2ahUKEwi0vP366rmGAxWb0AIHHVGFCHkQFnoECBsQAQ&usg=AOvVaw1UlSJxXmtPQHfkuY4FAfE8).

## Prerequisites
- python version later than 3.8
- pip installed
- metamask wallet already [set up](https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://www.alchemy.com/overviews/how-to-add-sepolia-to-metamask&ved=2ahUKEwi5ypf367mGAxWqwAIHHfYDCoUQFnoECCQQAQ&usg=AOvVaw1o5ZcnrWQSjj6vYco-pub4)

## Procedure
First, we are going to set up the development environment.  Remember, when using windows, it's recommended to use WSL2 for development purposes. I am using Ubuntu for this tutorial.

- Let's create a project folder named `testing`. 
`mkdir testing`
- Then, navigate through the folder: `cd testing`
- Create a virtual environment named `.venv`
`python3 -m venv .venv`and then, run `code .` to open vs code.
In the VS code terminal, activate the virtual environment by running `source .venv/bin/activate`

Next, we are going to install `apeworx` and all dependencies through a single command: `pip install eth-ape'[recommended-plugins]'`.

After a successful installation, we are now going to connect our project to the metamask wallet through creation of what is called an [account.](https://academy.apeworx.io/articles/account-tutorial.html)
- Run `ape accounts import meta_wallet`
In the above command, we have named our account 'meta_wallet'(you can name it anything you want). You'll then be prompted to enter `private key` and create a `passphrase` to encrypt your account.
```bash
Enter Private Key: 
Create Passphrase to encrypt account: 
Repeat for confirmation: 
```
To enter private key, go to your metamask wallet and copy a private key and securely save it somewhere. Paste it into the terminal and please note that you won't be able to see it so, don't paste more than once.
For a passphrase, create something that you won't forget.
To confirm if your account has been imported, run `ape accounts list`.

One more last thing to do for a successful set up is adding the Alchemy-api-key to our settings.
Run `code ~/.bashrc` to open the bashrc file. In this file, add the following line of code("YOUR_ALCHEMY_API_KEY" with the actual api key from alchemy) to the bottom end of it: `export WEB3_ALCHEMY_API_KEY="YOUR_ALCHEMY_API_KEY"
`
**Note:** If you are running your program on a testnet, please make sure that your alchemy ethereum app is a testnet not a mainnet.

Good that we are now done with the set up process, let's go for the actual business.
We shall start by initializing a project by running `ape init`.
This creates creates a project structure including; .build(for storage of artifacts), scripts folder, tests folder, contracts folder, and the ape.config-yaml file.

First, in the contracts folder, let's create a new file named `hello.vy` and add the following code which returns "Helloo, World!".
```python
#pragma version ^0.3.10

# A simple Vyper contract
@external
def say_hello() -> String[14]:
    return "Helloo, World!"
```
Next is to compile our code: `ape compile`.
Please note that after running the above command, a new file named `hello.json` is automatically created in the .build folder. This file contains the `abi` and `bytcode` of the contract.

Apart from abi, for our web3 library to be able interact with the deployed smart contract, it will need what we call a contract address and network. So, our next task is to create a another file named `deploy_hello.py` in the scripts folder for serving two purposes: 
1. Deploying script
2. Saving or adding the contact address and network details to the already existing hello.json file.
```python
import json
from ape import project, accounts

def main():
    # Load your account
    account = accounts.load('meta_wallet')
    
    # Deploy the contract
    contract = project.hello.deploy(sender=account)
    
    # Save the deployment details
    build_file = '.build/hello.json'
    with open(build_file, 'r') as file:
        contract_json = json.load(file)

    contract_json['networks'] = {
        'sepolia': {
            'address': contract.address
        }
    }

    with open(build_file, 'w') as file:
        json.dump(contract_json, file, indent=4)

    print(f"Contract deployed at address: {contract.address}")

if __name__ == "__main__":
    main()

```
Run `ape run deploy_hello --network ethereum:sepolia:alchemy` .
Congratulations if your deployment was a successful one.

Lastly, we are going to interact with our deployed smart contract using [web3.py](https://web3py.readthedocs.io/en/latest/quickstart.html) library. Create a `scripts/interact_hello.py` file and add the following code:
```python
import json
from web3 import Web3

# Define the path to the contract build file
contract_build_file = '.build/hello.json'

# Load the contract ABI and address from the build file
try:
    with open(contract_build_file, 'r') as file:
        contract_json = json.load(file)
        contract_abi = contract_json.get('abi')
        
        # Ensure the ABI is loaded
        if not contract_abi:
            raise ValueError("ABI not found in the contract build file.")

        # Check for the 'networks' key and retrieve the address
        networks = contract_json.get('networks')
        if not networks:
            raise KeyError("Networks key not found in the contract build file.")

        # Replace 'sepolia' with the actual network name used during deployment
        network_details = networks.get('sepolia')
        if not network_details:
            raise KeyError("Network details for 'sepolia' not found.")
        
        contract_address = network_details.get('address')
        if not contract_address:
            raise ValueError("Contract address not found in the network details.")


except (IOError, ValueError, KeyError) as e:
    print(f"Error loading contract build file: {e}")
    exit(1)

# Connect to the Ethereum network (e.g., Sepolia via Alchemy)
provider_url = 'Your_alchemy_url'
web3 = Web3(Web3.HTTPProvider(provider_url))

# Ensure the connection is successful
if not web3.is_connected():
    print("Failed to connect to the Ethereum network.")
    exit()

# Create a contract instance
contract = web3.eth.contract(address=contract_address, abi=contract_abi)

# Call the hello() function
def call_hello():
    try:
        message = contract.functions.say_hello().call()
        print(f"Contract message: {message}")
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    call_hello()

```
Run `python scripts/interact_hello.py`
Output: `Contract message: Helloo, World!`

Wow! we have had our smart contract compiled, deployed and interacted with all in vs code. If you found this article helpful, don't hesitate to give me a like and please follow for more. Thank You!