A Simple Vyper smart contract to fetch the price of BTC using Chainlink and Apeworx.

mosesmuwawu

Muwawu Moses

Posted on June 28, 2024

A Simple Vyper smart contract to fetch the price of BTC using Chainlink and Apeworx.

In this tutorial, we are going to navigate the basics of consuming a price feed oracle from Chainlink using the Apeworkx(ape) framework and vyper. We are going to connect to the ethereum network using Sepolia via Alchemy.

Prerequisites:

  1. Development environment already setup
  2. Metamask wallet set up
  3. Configured Metamask to use LINK tokens.

Procedure:

Since we have everything ready including the development environment, we can now begin. Activate your virtual environment in the terminal and run ape init to initialize the ape project. Go on and provide the project name of your choice.

Open the ape-config.yaml file and add the following code;

dependencies:
  - name: chainlink
    github: smartcontractkit/chainlink-mix
    branch: main
Enter fullscreen mode Exit fullscreen mode

The above code will ensure that chainlink is installed into our environment as a dependency.

Next, we are going to write our smart contracts. Navigate to the contracts folder and create a new folder interfaces. Inside the interfaces folder, add a file named AggregatorV3Interface.vy:

#pragma version ^0.3.10


@external
@view
def decimals() -> uint8:
    return 0


@external
@view
def description() -> String[1000]:
    return ""


@external
@view
def version() -> uint256:
    return 0


@external
@view
def getRoundData(_roundId: uint80) -> (uint80, int256, uint256, uint256, uint80):
    return (0, 0, 0, 0, 0)


@external
@view
def latestRoundData() -> (uint80, int256, uint256, uint256, uint80):
    return (0, 0, 0, 0, 0)
Enter fullscreen mode Exit fullscreen mode

Within the contracts folder, add a new file; test/PriceConsumer.vy

# SPDX-License-Identifier: MIT
#pragma version ^0.3.10

import contracts.interfaces.AggregatorV3Interface as AggregatorV3Interface

price_feed: public(AggregatorV3Interface)

@external
def __init__(_price_feed_address: address):
    self.price_feed = AggregatorV3Interface(_price_feed_address)

@external
@view
def get_latest_price() -> int256:
    a: uint80 = 0
    price: int256 = 0
    b: uint256 = 0
    c: uint256 = 0
    d: uint80 = 0
    (a, price, b, c, d) = self.price_feed.latestRoundData()
    return price
Enter fullscreen mode Exit fullscreen mode

Our code is now ready to compile. Please note that you should have an internet connection for this compilation to be successful because the project has to install chainlink as dependency before compiling.

Deployment:

In the scripts folder, let's create a file named deploy.py

from ape import accounts, project

def main():
    account = accounts.load("my_wallet")
    aggregator_address = "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43"
    contract = account.deploy(project.PriceConsumer, aggregator_address)
    print(f"Contract deployed at: {contract.address}")


if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Here, i will mainly talk about the aggregator_address = "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43". Where do we get it? Chainlink provides price feed addresses for all supported assets. So, you just have to copy and paste the address of your desired pair. To me, it's BTC-USD. To deploy the contract, run the command; ape run deploy --network ethereum:sepolia:alchemy

After successfully deploying the contract, copy the contract address because we are going to use for interacting with the contract.

Interacting with contract:

There are two ways in which we can interact with the deployed contract i.e through the console and through python scripts.

  • console

In your vs code terminal, run; ape console --network ethereum:sepolia:alchemy

In [1]: account = accounts.load("my_account")
Please enter passphrase to unlock 'my_account': 
In [2]: contract_address = "YourDeployedContractAddress"
In [3]: contract = project.PriceConsumer.at(contract_address)
In [4]: latest_price = contract.get_latest_price()
In [5]: print(f"The latest BTC price is: {latest_price / 1e8} USD")
The latest BTC price is: 61744.39100403 USD

Enter fullscreen mode Exit fullscreen mode

my_account is the alias used for your ape imported account from metamask.

  • Using scripts

First, we should update the ape-config.yaml file so as to set the default network from ethereum:local:test to ethereum:sepolia:alchemy

name: price-checker

dependencies:
  - name: chainlink
    github: smartcontractkit/chainlink-mix
    branch: main

vyper:
  version: 0.3.10

ethereum:
  default_network: sepolia
  sepolia:
    default_provider: alchemy

default_ecosystem: ethereum


Enter fullscreen mode Exit fullscreen mode

In the scripts folder, create a new file get_price.py

from ape import accounts, project,networks

def main():
    contract_address = "0x4Aac9382A3Cbb489DE2c67353a587983b9080343"


    # Load the deployed contract
    contract = project.PriceConsumer.at(contract_address)
    latest_price = contract.get_latest_price()
    print(f"The latest BTC price is: {latest_price / 1e8 } USD")

if __name__ == "__main__":
    main()

Enter fullscreen mode Exit fullscreen mode

For eductaion purposes, we can go for a more straight forward approach(without setting up the ape-config.yaml file) often used for multi-network scripting. get_price2.py:

import click
from ape.cli import ape_cli_context
from ape import project

@click.command()
@ape_cli_context()
def cli(cli_ctx):
    # There is no connection yet at this point.
    testnets = {
        "ethereum": ["sepolia"]
    }
    nm = cli_ctx.network_manager

    for ecosystem_name, networks in testnets.items():
        ecosystem = nm.ecosystems[ecosystem_name]

        for network_name in networks:
            # Start making connections.
            network = ecosystem.get_network(network_name)

            with network.use_provider("alchemy") as provider:
                print(f"Connected to {provider.network_choice}")
                contract_address = "0x4Aac9382A3Cbb489DE2c67353a587983b9080343"


                # Load the deployed contract
                contract = project.PriceConsumer.at(contract_address)
                latest_price = contract.get_latest_price()
                print(f"The latest BTC price is: {latest_price / 1e8 } USD")
Enter fullscreen mode Exit fullscreen mode

Congratulations if you have reached up to this stage. Please like and follow if you found this post helpful

💖 💪 🙅 🚩
mosesmuwawu
Muwawu Moses

Posted on June 28, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related