Rust: Talk to the Ethereum Blockchain

Rust is amazing and with the web3 crate, you can talk to the Ethereum blockchain.

Objective

In this tutorial, we will connect to an Ethereum node (provided by infura) using the web3 crate and fetch the ether balance of a particular address.

But wait, what is Infura and why do we need access to an Ethereum node?

You can think of the Ethereum Blockchain as many computers (or nodes) connected to each other. Now, to talk to the blockchain you will need access to one of these nodes, won't you?

But, Running a node is not always feasible for everyone. Enter Infura, which provides access to an Ethereum node using its APIs.

GitHub repo containing all the code

Find the code here: https://github.com/codeTIT4N/rust-web3-basics

You can star/fork this over github.

Dependencies needed

The dependencies we need for this are:

Setting up environment variables

Now create a .env file which will have 2 environment variables:

  1. INFURA_WSS: This will have the web socket URL from Infura. It will look something like "wss://mainnet.infura.io/ws/v3<API_KEY>". Here replace API_KEY will be your API key generated by Infura. This will give us access to an ethereum node.

  2. ACCOUNT_ADDRESS: Here put any ethereum account address for which you want to fetch the balance.

For reference: https://github.com/codeTIT4N/rust-web3-basics/blob/master/.env.example

Importing types for handling web3 data

use web3::types::{H160, U256};

Here we are importing H160 and U256 types from the web3 crate.

The H160 type will be used for Ethereum addresses and U256 for 256-bit unsigned integers.

Code walkthrough

The code looks like:

use std::env;
use std::str::FromStr;

use web3::types::{H160, U256}; 

#[tokio::main]
async fn main() -> web3::Result<()> {
    dotenv::dotenv().ok();

    let websocket = web3::transports::WebSocket::new(&env::var("INFURA_WSS").unwrap()).await?;

    let web3s = web3::Web3::new(websocket);

    let account = H160::from_str(&env::var("ACCOUNT_ADDRESS").unwrap());

    let balance = web3s.eth().balance(account.unwrap(), None).await?;

    println!("Wei balance of {:?}: {:?} wei", account.unwrap(), balance);

    let wei_conv: U256 = U256::exp10(18);

    println!(
        "ETH balance of {:?}: {} ETH",
        account.unwrap(),
        balance.checked_div(wei_conv).unwrap()
    );
    Ok(())
}

After setting up tokio and dotenv, I have created connection with the Ethereum Blockchain like this:

let websocket = web3::transports::WebSocket::new(&env::var("INFURA_WSS").unwrap()).await?;

Here, note we are taking the wss link from the .env file and also using await since this will be an asynchronous connection.

Next, create a web3 instance using the websocket:

let web3s = web3::Web3::new(websocket);

Get the account from the environment variables:

let account = H160::from_str(&env::var("ACCOUNT_ADDRESS").unwrap());

Now, fetch the balance using the web3 instance like:

let balance = web3s.eth().balance(account.unwrap(), None).await?;

This will give the balance in wei.

Now, lets convert this to ether. Since:

$$1 ETH = 10^{18} wei$$

We can get this value in rust using:

 let wei_conv: U256 = U256::exp10(18);

Now, we will divide the wei balance by this number to get the approximate ether balance:

println!(
        "ETH balance of {:?}: {} ETH",
        account.unwrap(),
        balance.checked_div(wei_conv).unwrap()
    );

This will print the approximate ETH balance.

Output

Run the code using

cargo run

Thanks!