use alloy::providers::{Provider, ProviderBuilder};
use alloy::network::AnyNetwork;
use alloy::primitives::U256;
use crate::onchain::{NetworkConfig, OnchainError, Result};
#[derive(Clone)]
pub struct OnchainProvider {
pub(crate) provider: alloy::providers::DynProvider<AnyNetwork>,
pub(crate) network: NetworkConfig,
}
impl OnchainProvider {
pub fn new(network: &NetworkConfig) -> Result<Self> {
let url = network.rpc_url.parse().map_err(|e| {
OnchainError::NetworkError(format!("Invalid RPC URL: {}", e))
})?;
let provider = ProviderBuilder::new()
.network::<AnyNetwork>()
.connect_http(url);
Ok(Self {
provider: provider.erased(),
network: network.clone(),
})
}
pub fn provider(&self) -> &alloy::providers::DynProvider<AnyNetwork> {
&self.provider
}
pub fn network(&self) -> &NetworkConfig {
&self.network
}
pub fn chain_id(&self) -> u64 {
self.network.chain_id
}
pub async fn get_gas_price(&self) -> Result<U256> {
let gas_price = self.provider
.get_gas_price()
.await
.map_err(|e| OnchainError::NetworkError(format!("Failed to get gas price: {}", e)))?;
Ok(U256::from(gas_price))
}
pub async fn get_block_number(&self) -> Result<u64> {
self.provider
.get_block_number()
.await
.map_err(|e| OnchainError::NetworkError(format!("Failed to get block number: {}", e)))
}
pub async fn is_connected(&self) -> bool {
self.provider.get_chain_id().await.is_ok()
}
}
impl std::fmt::Debug for OnchainProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OnchainProvider")
.field("chain_id", &self.network.chain_id)
.field("rpc_url", &self.network.rpc_url)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_provider_debug() {
let network = NetworkConfig::polygon_mainnet();
let url = network.rpc_url.parse().unwrap();
let provider = ProviderBuilder::new()
.network::<AnyNetwork>()
.connect_http(url)
.erased();
let provider = OnchainProvider {
provider,
network,
};
let debug_str = format!("{:?}", provider);
assert!(debug_str.contains("OnchainProvider"));
assert!(debug_str.contains("137"));
}
#[test]
fn test_chain_id() {
let network = NetworkConfig::polygon_mainnet();
let url = network.rpc_url.parse().unwrap();
let provider = ProviderBuilder::new()
.network::<AnyNetwork>()
.connect_http(url)
.erased();
let provider = OnchainProvider {
provider,
network: network.clone(),
};
assert_eq!(provider.chain_id(), 137);
assert_eq!(provider.network().chain_id, 137);
}
}