SequencerClient
This library is used to read messages from the arbitrum sequencer feed and parses them into alloy transactions.
Features
It supports the following transaction types
- L2 Messages
- Legacy transactions
- EIP-2930 transactions
- EIP-1559 transactions
- EIP-7702 transactions
- Arbitrum Specific Transactions
- SubmitRetryable
- More to come (it's a wip)
Motivation
Listening to the sequencer feed is generally faster than listening through
subscribing to logs. Since existing libraries ignore batch transactions, which
seemingly make up for 80% of transactions, I created this library.
In the long run, types from this library could be extracted into a seperate crate at some point to support arbitrum tooling in rust.
Example
use color_eyre::install;
use futures_util::stream::StreamExt;
use sequencer_client::reader::SequencerReader;
#[tokio::main()]
async fn main() {
let url = "wss://arb1-feed.arbitrum.io/feed";
let subscriber = tracing_subscriber::FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.finish();
tracing::subscriber::set_global_default(subscriber)
.expect("Failed to set global default subscriber");
tracing::info!("Starting application");
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("Failed to install rustls crypto provider");
tracing::info!("Connecting to sequencer at {}", url);
let reader = SequencerReader::new(url, 42161).await;
let mut stream = reader.into_stream();
tracing::info!("Created stream, starting to read messages...");
let mut count = 0;
let timeout = std::time::Duration::from_secs(30);
loop {
match tokio::time::timeout(timeout, stream.next()).await {
Ok(Some(msg_result)) => {
count += 1;
tracing::info!("Received message #{}", count);
match msg_result {
Ok(msg) => match msg.tx.inner() {
sequencer_client::types::transactions::ArbTxEnvelope::Legacy(signed) => {
tracing::info!(
"Received legacy transaction with hash {}",
signed.hash()
);
}
sequencer_client::types::transactions::ArbTxEnvelope::Eip2930(signed) => {
tracing::info!(
"Received EIP-2930 transaction with hash {}",
signed.hash()
);
}
sequencer_client::types::transactions::ArbTxEnvelope::Eip1559(signed) => {
tracing::info!(
"Received EIP-1559 transaction with hash {}",
signed.hash()
);
}
sequencer_client::types::transactions::ArbTxEnvelope::Eip7702(signed) => {
tracing::info!(
"Received EIP-7702 transaction with hash {}",
signed.hash()
);
}
sequencer_client::types::transactions::ArbTxEnvelope::ArbRetryable(
tx_submit_retryable,
) => {
tracing::info!(
"Received ArbRetryable transaction with hash {}",
tx_submit_retryable.tx_hash()
);
}
},
Err(e) => {
tracing::error!("Error in received message: {:?}", e);
}
}
}
Ok(None) => {
tracing::warn!("Stream ended, exiting");
break;
}
Err(_) => {
tracing::warn!(
"No messages received in the last {} seconds",
timeout.as_secs()
);
tracing::info!("Waiting for messages...");
}
}
}
}