mod accounts_provider;
pub mod autoswap;
pub mod charge;
mod error;
mod provider;
pub mod session;
pub mod signing;
pub use accounts_provider::TempoAccountsProvider;
pub use autoswap::AutoswapConfig;
pub use error::TempoClientError;
pub use provider::TempoProvider;
pub(crate) fn rpc_provider(
rpc_url: reqwest::Url,
) -> alloy::providers::RootProvider<tempo_alloy::TempoNetwork> {
let retry = alloy::transports::layers::RetryBackoffLayer::new(20, 10, 1_000);
let client = alloy::rpc::client::ClientBuilder::default()
.layer(retry)
.http(rpc_url);
alloy::providers::ProviderBuilder::<_, _, tempo_alloy::TempoNetwork>::default()
.connect_client(client)
}
pub const MAX_FEE_PER_GAS: u128 = 20_000_000_000 * 2 + 1_000_000_000;
pub const MAX_PRIORITY_FEE_PER_GAS: u128 = 1_000_000_000;
#[cfg(test)]
mod tests {
use super::rpc_provider;
use alloy::providers::Provider;
use axum::{extract::State, routing::post, Json, Router};
use serde_json::{json, Value};
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
#[tokio::test]
async fn rpc_provider_retries_tempo_rate_limits() {
async fn rpc(
State(attempts): State<Arc<AtomicUsize>>,
Json(request): Json<Value>,
) -> Json<Value> {
let attempt = attempts.fetch_add(1, Ordering::SeqCst);
let id = request.get("id").cloned().unwrap_or(Value::Null);
if attempt < 2 {
Json(json!({
"jsonrpc": "2.0",
"id": id,
"error": {
"code": -32005,
"message": "rate limited, try again in 1ms"
}
}))
} else {
Json(json!({"jsonrpc": "2.0", "id": id, "result": "0x1079"}))
}
}
let attempts = Arc::new(AtomicUsize::new(0));
let app = Router::new()
.route("/", post(rpc))
.with_state(attempts.clone());
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let url = format!("http://{}/", listener.local_addr().unwrap())
.parse()
.unwrap();
let server = tokio::spawn(async move {
axum::serve(listener, app).await.unwrap();
});
let chain_id = rpc_provider(url).get_chain_id().await.unwrap();
assert_eq!(chain_id, 4217);
assert_eq!(attempts.load(Ordering::SeqCst), 3);
server.abort();
}
}