Skip to content

mateuszm-arianelabs/rust-eth-client-research

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

web3 rs

https://crates.io/crates/web3

Ethereum JSON-RPC multi-transport client. Rust implementation of the Web3.js library. This is the oldest package, allowing contract calls, batch requests, and sending transactions. It supports the async runtime tokio and transport via HTTP, IPC, and WebSockets.

If you want to deploy a contract, you need ready bin and ABI files, as the library doesn't provide any solution for that. In the documentation, they recommend using solc outside of Rust.

The library provides contract types, transaction, transaction receipt, block, work, and syncing but doesn't generate types and methods from ABI. When you want to call a contract method, you need to pass the method name as a string and parameters in a tuple.

Library status As they typed on the crate page, this package is barely maintained, and they are looking for an active maintainer. They recommend using ethers-rs for new projects, but for now, it's not recommended either, as will be discussed later.

Docs In my opinion, the documentation is weak, but at least the library provides some examples of the most popular use cases.

Example in Hedera You can find example of using Web3 rs with Hedera in web3rs dir

Examples:

Basic interaction with chain:

#[tokio::main]  
async fn main() -> web3::Result<()> {  
    let transport = web3::transports::Http::new("...")?;  
    let web3 = web3::Web3::new(transport);  
  
    println!("Calling accounts.");  
    let mut accounts = web3.eth().accounts().await?;  
    println!("Accounts: {:?}", accounts);  
    accounts.push("...".parse().unwrap());  
  
    println!("Calling balance.");  
    for account in accounts {  
        let balance = web3.eth().balance(account, None).await?;  
        println!("Balance of {:?}: {}", account, balance);  
    }  
    Ok(())  
}

Deploy and interact with contract:

use hex_literal::hex;
use web3::{
    contract::{Contract, Options},
    types::U256,
};

#[tokio::main]
async fn main() -> web3::contract::Result<()> {
    let _ = env_logger::try_init();
    let http = web3::transports::Http::new("...")?;
    let web3 = web3::Web3::new(http);

    let my_account = hex!("...").into();
    // Get the contract bytecode for instance from Solidity compiler
    let bytecode = include_str!("...").trim_end();
    // Deploying a contract
    let contract = Contract::deploy(web3.eth(), include_bytes!("..."))?
        .confirmations(0)
        .options(Options::with(|opt| {
            opt.value = Some(5.into());
            opt.gas_price = Some(5.into());
            opt.gas = Some(3_000_000.into());
        }))
        .execute(
            bytecode,
            (U256::from(1_000_000_u64), "My Token".to_owned(), 3u64, "MT".to_owned()),
            my_account,
        )
        .await?;

    let result = contract.query("balanceOf", (my_account,), None, Options::default(), None);
    // Make sure to specify the expected return type, to prevent ambiguous compiler
    // errors about `Detokenize` missing for `()`.
    let balance_of: U256 = result.await?;
    assert_eq!(balance_of, 1_000_000.into());

    // Accessing existing contract
    let contract_address = contract.address();
    let contract = Contract::from_json(
        web3.eth(),
        contract_address,
        include_bytes!("..."),
    )?;

    let result = contract.query("balanceOf", (my_account,), None, Options::default(), None);
    let balance_of: U256 = result.await?;
    assert_eq!(balance_of, 1_000_000.into());

    Ok(())
}

ethers rs

https://crates.io/crates/ethers Complete Ethereum & Celo library and wallet implementation in Rust. This crate is created to work with Ethereum and Celo chains, with rich features listed below.

Features

  • Ethereum JSON-RPC Client
  • Interacting with and deploying smart contracts
  • Type-safe smart contract bindings code generation
  • Querying past events
  • Event monitoring as Streams
  • ENS as a first-class citizen
  • Celo support
  • Polygon support
  • Avalanche support
  • Optimism support
  • Websockets / eth_subscribe
  • Hardware wallet support
  • Parity APIs (tracing, parity_blockWithReceipts)
  • Geth TxPool API

Unlike web3-rs, ethers provides tools for compilation and abigen. The library looks more mature and more developer-friendly.

Library status They write on their GitHub: "We are deprecating ethers-rs for Alloy."

Docs Ethers rs has better documentation represented by the book at https://www.gakonst.com/ethers-rs/. However, it is incomplete and provides examples only for some parts.

Example in Hedera You can find example of using Ethers rs with Hedera in ethers dir

Examples:

deployment and interact with contract

use ethers::{
    contract::abigen,
    core::utils::Anvil,
    middleware::SignerMiddleware,
    providers::{Http, Provider},
    signers::{LocalWallet, Signer},
};
use eyre::Result;
use std::{convert::TryFrom, sync::Arc, time::Duration};

// Generate the type-safe contract bindings by providing the json artifact
// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact:
// `{"abi": [..], "bin": "..."}` , `{"abi": [..], "bytecode": {"object": "..."}}` or
// `{"abi": [..], "bytecode": "..."}` this will embedd the bytecode in a variable `GREETER_BYTECODE`
abigen!(Greeter, "...",);

#[tokio::main]
async fn main() -> Result<()> {
    // 1. compile the contract (note this requires that you are inside the `examples` directory) and
    // launch anvil
    let anvil = Anvil::new().spawn();

    // 2. instantiate our wallet
    let wallet: LocalWallet = anvil.keys()[0].clone().into();

    // 3. connect to the network
    let provider =
        Provider::<Http>::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64));

    // 4. instantiate the client with the wallet
    let client = Arc::new(SignerMiddleware::new(provider, wallet.with_chain_id(anvil.chain_id())));

    // 5. deploy contract
    let greeter_contract =
        Greeter::deploy(client, "Hello World!".to_string()).unwrap().send().await.unwrap();

    // 6. call contract function
    let greeting = greeter_contract.greet().call().await.unwrap();
    assert_eq!("Hello World!", greeting);

    Ok(())
}

alloy-core

https://crates.io/crates/alloy-core

Alloy implements high-performance, well-tested, and documented libraries for interacting with Ethereum and other EVM-based chains. It is a rewrite of ethers-rs from the ground up, with exciting new features, high performance, and excellent documentation.

Alloy is a collection of several crates around the Ethereum ecosystem. For our use case, we'll use alloy-core. It's the youngest library on the list, but that doesn't mean it's the worst. On the contrary, as a rewrite of ethers-rs, many known problems in the previous libraries won't appear.

Library status
It's a relatively new library but highly developed and will probably become the most popular choice soon.

Docs
Alloy documentation contains rich examples of most use cases, with comments provided to explain everything line by line.

Example in Hedera You can find example of using Alloy core with Hedera in alloy dir

Example contract deployment and interaction.

//! Example of deploying a contract at runtime from Solidity bytecode to Anvil and interacting with
//! it.

use alloy::{
    hex,
    network::{EthereumWallet, ReceiptResponse, TransactionBuilder},
    node_bindings::Anvil,
    primitives::U256,
    providers::{Provider, ProviderBuilder},
    rpc::types::TransactionRequest,
    signers::local::PrivateKeySigner,
    sol,
};
use eyre::Result;

// If you have the bytecode known at build time, use the `deploy_from_contract` example.
// This method benefits from using bytecode at runtime, e.g., from newly deployed contracts, to
// analyze the behavior.
sol! {
    #[allow(missing_docs)]
    #[sol(rpc)]
    contract Counter {
        uint256 public number;

        function setNumber(uint256 newNumber) public {
            number = newNumber;
        }

        function increment() public {
            number++;
        }
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    // Spin up a local Anvil node.
    // Ensure `anvil` is available in $PATH.
    let anvil = Anvil::new().try_spawn()?;

    // Set up signer from the first default Anvil account (Alice).
    let signer: PrivateKeySigner = anvil.keys()[0].clone().into();
    let wallet = EthereumWallet::from(signer);

    println!("Anvil running at `{}`", anvil.endpoint());

    // Create a provider with the wallet.
    let rpc_url = anvil.endpoint().parse()?;
    let provider =
        ProviderBuilder::new().with_recommended_fillers().wallet(wallet).on_http(rpc_url);

    // Deploy the `Counter` contract from bytecode at runtime.
    let bytecode = hex::decode(
        // solc v0.8.26; solc Counter.sol --via-ir --optimize --bin
        "..."
    )?;
    let tx = TransactionRequest::default().with_deploy_code(bytecode);

    // Deploy the contract.
    let receipt = provider.send_transaction(tx).await?.get_receipt().await?;

    let contract_address = receipt.contract_address().expect("Failed to get contract address");
    let contract = Counter::new(contract_address, &provider);
    println!("Deployed contract at address: {}", contract.address());

    // Set number
    let builder = contract.setNumber(U256::from(42));
    let tx_hash = builder.send().await?.watch().await?;

    println!("Set number to 42: {tx_hash}");

    // Increment the number to 43.
    let builder = contract.increment();
    let tx_hash = builder.send().await?.watch().await?;

    println!("Incremented number: {tx_hash}");

    // Retrieve the number, which should be 43.
    let builder = contract.number();
    let number = builder.call().await?.number.to_string();

    println!("Retrieved number: {number}");

    Ok(())
}

Summary

Web3-rs is the oldest library that provides a more low-level implementation. It probably won't be used in new projects due to better alternatives.

Ethers rs is the most mature library, offering a full toolchain. It is currently the most popular choice, but it lacks good documentation and there are no plans for future maintenance because of Alloy, as it is currently deprecated.

Alloy-core is a rewrite of Ethers rs. It provides good documentation, rich examples, and a full toolchain that enhances the developer experience. It is the only library with a bright future and a long-term maintenance plan. The downside is that it is not as popular as Ethers, but we are in a situation where Alloy is recommended in the main Ethers repository, so this will soon change.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages