Example: event_multiplexer

Example

To run this example:

  • Clone the examples repository: git clone git@github.com:alloy-rs/examples.git
  • Run: cargo run --example event_multiplexer
//! Example of multiplexing the watching of event logs.

use std::str::FromStr;

use alloy::{
    node_bindings::Anvil,
    primitives::I256,
    providers::{ProviderBuilder, WsConnect},
    sol,
    sol_types::SolEvent,
};
use eyre::Result;
use futures_util::StreamExt;

// Codegen from embedded Solidity code and precompiled bytecode.
// solc v0.8.26; solc EventMultiplexer.sol --via-ir --optimize --bin
sol!(
    #[allow(missing_docs)]
    #[sol(rpc, bytecode = "60808060405234601557610207908161001b8239f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c80634350913814610156578063a5f3c23b14610108578063adefc37b146100ba5763bbe93d911461004857600080fd5b346100b557610056366101bb565b818102919060008212600160ff1b82141661009f57818305149015171561009f57337fd7a123d4c8e44db3186e04b9c96c102287276929c930f2e8abcaa555ef5dcacc600080a3005b634e487b7160e01b600052601160045260246000fd5b600080fd5b346100b5576100c8366101bb565b906000828203921281831281169183139015161761009f57337f32e913bf2ad35da1e845597618bb9f3f80642a68dd39f30a093a7838aa61fb27600080a3005b346100b557610116366101bb565b906000828201928312911290801582169115161761009f57337f6da406ea462447ed7804b4a4dc69c67b53d3d45a50381ae3e9cf878c9d7c23df600080a3005b346100b557610164366101bb565b9081156101a557600160ff1b811460001983141661009f5705337f1c1e8bbe327890ea8d3f5b22370a56c3fcef7ff82f306161f64647fe5d285881600080a3005b634e487b7160e01b600052601260045260246000fd5b60409060031901126100b557600435906024359056fea2646970667358221220d876fbacf1e90fc174532f3525420c446351b467f788f9d7a726a7d55045909664736f6c634300081a0033")]
    contract EventMultiplexer {
        event Add(address indexed sender, int256 indexed value);
        event Sub(address indexed sender, int256 indexed value);
        event Mul(address indexed sender, int256 indexed value);
        event Div(address indexed sender, int256 indexed value);

        function add(int256 a, int256 b) public {
            emit Add(msg.sender, a + b);
        }

        function sub(int256 a, int256 b) public {
            emit Sub(msg.sender, a - b);
        }

        function mul(int256 a, int256 b) public {
            emit Mul(msg.sender, a * b);
        }

        function div(int256 a, int256 b) public {
            emit Div(msg.sender, a / b);
        }
    }
);

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

    // Create a provider.
    let ws = WsConnect::new(anvil.ws_endpoint());
    let provider = ProviderBuilder::new().on_ws(ws).await?;

    // Deploy the `EventExample` contract.
    let contract = EventMultiplexer::deploy(provider).await?;

    println!("Deployed contract at: {}", contract.address());

    // Create filters for each event.
    let add_filter = contract.Add_filter().watch().await?;
    let sub_filter = contract.Sub_filter().watch().await?;
    let mul_filter = contract.Mul_filter().watch().await?;
    let div_filter = contract.Div_filter().watch().await?;

    let a = I256::from_str("1")?;
    let b = I256::from_str("1")?;

    // Build the transaction calls.
    let add_call = contract.add(a, b);
    let sub_call = contract.sub(a, b);
    let mul_call = contract.mul(a, b);
    let div_call = contract.div(a, b);

    // Send the transaction calls.
    let _ = add_call.send().await?;
    let _ = sub_call.send().await?;
    let _ = mul_call.send().await?;
    let _ = div_call.send().await?;

    // Convert the filters into streams.
    let mut add_stream = add_filter.into_stream();
    let mut sub_stream = sub_filter.into_stream();
    let mut mul_stream = mul_filter.into_stream();
    let mut div_stream = div_filter.into_stream();

    let add_log = &EventMultiplexer::Add::SIGNATURE_HASH;
    let sub_log = &EventMultiplexer::Sub::SIGNATURE_HASH;
    let mul_log = &EventMultiplexer::Mul::SIGNATURE_HASH;
    let div_log = &EventMultiplexer::Div::SIGNATURE_HASH;

    // Use tokio::select! to multiplex the streams and capture the log
    // tokio::select! will return the first event that arrives from any of the streams
    // The for loop helps capture all the logs.
    for _ in 0..4 {
        let log = tokio::select! {
            Some(log) = add_stream.next() => {
                log?.1
            }
            Some(log) = sub_stream.next() => {
                log?.1
            }
            Some(log) = mul_stream.next() => {
                log?.1
            }
            Some(log) = div_stream.next() => {
                log?.1
            }
        };

        let topic = &log.topics()[0];

        if topic == add_log {
            println!("Received Add: {log:?}");
        } else if topic == sub_log {
            println!("Received Sub: {log:?}");
        } else if topic == mul_log {
            println!("Received Mul: {log:?}");
        } else if topic == div_log {
            println!("Received Div: {log:?}");
        }
    }

    Ok(())
}

Find the source code on Github here.