Skip to content

Getting Started

Quickly connect to a blockchain using alloy

Overview

Alloy is a high-performance Rust toolkit for Ethereum and EVM-based blockchains providing developers with:

  • High Performance: Optimized primitives with up to 60% faster U256 operations and 10x faster ABI encoding
  • Developer Experience: Intuitive API for interacting with Smart contracts via the sol! macro
  • Chain-Agnostic Type System: Multi-chain support without feature flags or type casting
  • Extensibility: Customizable provider architecture with layers and fillers

Installation

Install alloy to any cargo project using the command line. See Installation for more details on the various features flags.

cargo
cargo add alloy

Quick Start

1. Sending ETH

This example shows how to send 100 ETH using the TransactionBuilder

use alloy::{
    network::TransactionBuilder,
    primitives::{
        address,
        utils::{format_ether, Unit},
        U256,
    },
    providers::{Provider, ProviderBuilder},
    rpc::types::TransactionRequest,
    signers::local::PrivateKeySigner,
};
use std::error::Error;
 
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Initialize a signer with a private key
    let signer: PrivateKeySigner =
        "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse()?;
 
    // Instantiate a provider with the signer
    // This example uses a local Anvil node
    let provider = ProviderBuilder::new()
        .wallet(signer)
        .connect("https://reth-ethereum.ithaca.xyz/rpc")
        .await?;
 
    // Prepare a transaction request to send 100 ETH to Alice
    let alice = address!("0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
    let value = Unit::ETHER.wei().saturating_mul(U256::from(100));
    let tx = TransactionRequest::default()
        .with_to(alice)
        .with_value(value);
 
    // Send the transaction and wait for the broadcast
    let pending_tx = provider.send_transaction(tx).await?;
    println!("Pending transaction... {}", pending_tx.tx_hash());
 
    // Wait for the transaction to be included and get the receipt
    let receipt = pending_tx.get_receipt().await?;
    println!(
        "Transaction included in block {}",
        receipt.block_number.expect("Failed to get block number")
    );
 
    println!("Transferred {:.5} ETH to {alice}", format_ether(value));
 
    Ok(())
}

2. Interacting with Smart Contracts

Alloy's sol! macro makes working with smart contracts intuitive by letting you write Solidity directly in Rust:

use alloy::{
    primitives::{
        address,
        utils::{format_ether, Unit},
        U256,
    },
    providers::ProviderBuilder,
    signers::local::PrivateKeySigner,
    sol,
};
use std::error::Error;
 
// Generate bindings for the WETH9 contract
sol! {
    #[sol(rpc)]
    contract WETH9 {
        function deposit() public payable;
        function balanceOf(address) public view returns (uint256);
        function withdraw(uint amount) public;
    }
}
 
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Initialize a signer with a private key
    let signer: PrivateKeySigner =
        "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse()?;
 
    // Instantiate a provider with the signer
    let provider = ProviderBuilder::new()
        .wallet(signer)
        .on_anvil_with_config(|a| a.fork("https://reth-ethereum.ithaca.xyz/rpc"));
 
    // Setup WETH contract instance
    let weth_address = address!("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2");
    let weth = WETH9::new(weth_address, provider.clone());
 
    // Read initial balance
    let from_address = signer.address();
    let initial_balance = weth.balanceOf(from_address).call().await?;
    println!("Initial WETH balance: {} WETH", format_ether(initial_balance));
 
    // Write: Deposit ETH to get WETH
    let deposit_amount = Unit::ETHER.wei().saturating_mul(U256::from(10));
    let deposit_tx = weth.deposit().value(deposit_amount).send().await?;
    let deposit_receipt = deposit_tx.get_receipt().await?;
    println!(
        "Deposited ETH in block {}",
        deposit_receipt.block_number.expect("Failed to get block number")
    );
 
    // Read: Check updated balance after deposit
    let new_balance = weth.balanceOf(from_address).call().await?;
    println!("New WETH balance: {} WETH", format_ether(new_balance));
 
    // Write: Withdraw some WETH back to ETH
    let withdraw_amount = Unit::ETHER.wei().saturating_mul(U256::from(5));
    let withdraw_tx = weth.withdraw(withdraw_amount).send().await?;
    let withdraw_receipt = withdraw_tx.get_receipt().await?;
    println!(
        "Withdrew ETH in block {}",
        withdraw_receipt.block_number.expect("Failed to get block number")
    );
 
    // Read: Final balance check
    let final_balance = weth.balanceOf(from_address).call().await?;
    println!("Final WETH balance: {} WETH", format_ether(final_balance));
 
    Ok(())
}

3. Monitoring Blockchain Activity

This example shows how to monitor blocks and track the balance of a famous contract in real-time:

use alloy::{
    primitives::{Address, utils::format_ether},
    providers::{Provider, ProviderBuilder},
};
use std::error::Error;
use futures::StreamExt;
 
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // Connect to an Ethereum node via WebSocket
    let provider = ProviderBuilder::new()
        .connect_ws("wss://ethereum.ithaca.xyz/ws")
        .await?;
 
    // Uniswap V3 ETH-USDC Pool address
    let uniswap_pool = "0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8".parse::<Address>()?;
 
    // Subscribe to new blocks
    let mut block_stream = provider.subscribe_blocks().await?.into_stream();
    println!("🔄 Monitoring for new blocks...");
 
    // Process each new block as it arrives
    while let Some(block) = block_stream.next().await {
        println!("🧱 Block #{}: {}", block.header.number, block.header.hash);
 
        // Get contract balance at this block
        let balance = provider
            .get_balance(uniswap_pool)
            .block_id(block.header.number.into())
            .await?;
 
        // Format the balance in ETH
        println!("💰 Uniswap V3 ETH-USDC Pool balance: {} ETH", format_ether(balance));
    }
 
    Ok(())
}

Guides

Check out our Guides to see more practical use cases, including: