diff --git a/SUPPORTED_CHAINS.md b/SUPPORTED_CHAINS.md
index adc6ba3a7c..0614113457 100644
--- a/SUPPORTED_CHAINS.md
+++ b/SUPPORTED_CHAINS.md
@@ -30,12 +30,14 @@ Chain name with associated `chainId` query param to use.
| Ethereum Holesky | eip155:17000 |
| Arbitrum | eip155:42161 |
| Celo | eip155:42220 |
+| Etherlink | eip155:42793 |
| Avalanche Fuji Testnet [1](#footnote1) | eip155:43113 |
| Avalanche C-Chain | eip155:43114 |
| Linea [1](#footnote1) | eip155:59144 |
| Polygon Amoy [1](#footnote1) | eip155:80002 |
| Berachain bArtio [1](#footnote1) | eip155:80084 |
| Base Sepolia | eip155:84532 |
+| Etherlink Testnet | eip155:128123 |
| Arbitrum Sepolia | eip155:421614 |
| Scroll Mainnet [1](#footnote1) | eip155:534352 |
| Scroll Sepolia Testnet [1](#footnote1) | eip155:534351 |
diff --git a/src/env/etherlink.rs b/src/env/etherlink.rs
new file mode 100644
index 0000000000..47b7d3f96a
--- /dev/null
+++ b/src/env/etherlink.rs
@@ -0,0 +1,55 @@
+use {
+ super::ProviderConfig,
+ crate::providers::{Priority, Weight},
+ std::collections::HashMap,
+};
+
+#[derive(Debug)]
+pub struct EtherlinkConfig {
+ pub supported_chains: HashMap,
+}
+
+impl Default for EtherlinkConfig {
+ fn default() -> Self {
+ Self {
+ supported_chains: default_supported_chains(),
+ }
+ }
+}
+
+impl ProviderConfig for EtherlinkConfig {
+ fn supported_chains(self) -> HashMap {
+ self.supported_chains
+ }
+
+ fn supported_ws_chains(self) -> HashMap {
+ HashMap::new()
+ }
+
+ fn provider_kind(&self) -> crate::providers::ProviderKind {
+ crate::providers::ProviderKind::Etherlink
+ }
+}
+
+fn default_supported_chains() -> HashMap {
+ // Keep in-sync with SUPPORTED_CHAINS.md
+
+ HashMap::from([
+ // Etherlink Mainnet
+ (
+ "eip155:42793".into(),
+ (
+ "https://node.mainnet.etherlink.com".into(),
+ Weight::new(Priority::Normal).unwrap(),
+ ),
+ ),
+ // Etherlink Testnet
+ (
+ "eip155:128123".into(),
+ (
+ "https://node.ghostnet.etherlink.com".into(),
+ Weight::new(Priority::Normal).unwrap(),
+ ),
+ ),
+ ])
+}
\ No newline at end of file
diff --git a/src/env/mod.rs b/src/env/mod.rs
index 3a1422c31b..88765803cc 100644
--- a/src/env/mod.rs
+++ b/src/env/mod.rs
@@ -16,7 +16,7 @@ use {
};
pub use {
allnodes::*, arbitrum::*, aurora::*, base::*, berachain::*, binance::*, drpc::*, dune::*,
- getblock::*, infura::*, lava::*, mantle::*, morph::*, near::*, odyssey::*, pokt::*,
+ etherlink::*, getblock::*, infura::*, lava::*, mantle::*, morph::*, near::*, odyssey::*, pokt::*,
publicnode::*, quicknode::*, server::*, solscan::*, syndica::*, unichain::*, wemix::*,
zerion::*, zksync::*, zora::*,
};
@@ -28,6 +28,7 @@ mod berachain;
mod binance;
mod drpc;
mod dune;
+mod etherlink;
mod getblock;
mod infura;
mod lava;
diff --git a/src/lib.rs b/src/lib.rs
index 614aba2068..d0e64cec33 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,7 +23,7 @@ use {
},
env::{
AllnodesConfig, ArbitrumConfig, AuroraConfig, BaseConfig, BerachainConfig, BinanceConfig,
- DrpcConfig, DuneConfig, GetBlockConfig, InfuraConfig, LavaConfig, MantleConfig,
+ DrpcConfig, DuneConfig, EtherlinkConfig, GetBlockConfig, InfuraConfig, LavaConfig, MantleConfig,
MorphConfig, NearConfig, OdysseyConfig, PoktConfig, PublicnodeConfig, QuicknodeConfig,
SolScanConfig, SyndicaConfig, UnichainConfig, WemixConfig, ZKSyncConfig, ZerionConfig,
ZoraConfig,
@@ -33,7 +33,7 @@ use {
hyper::{header::HeaderName, http, server::conn::AddrIncoming, Body, Server},
providers::{
AllnodesProvider, ArbitrumProvider, AuroraProvider, BaseProvider, BerachainProvider,
- BinanceProvider, DrpcProvider, DuneProvider, GetBlockProvider, InfuraProvider,
+ BinanceProvider, DrpcProvider, DuneProvider, EtherlinkProvider, GetBlockProvider, InfuraProvider,
InfuraWsProvider, LavaProvider, MantleProvider, MorphProvider, NearProvider,
OdysseyProvider, PoktProvider, ProviderRepository, PublicnodeProvider, QuicknodeProvider,
SolScanProvider, SyndicaProvider, UnichainProvider, WemixProvider, ZKSyncProvider,
@@ -526,6 +526,7 @@ fn init_providers(config: &ProvidersConfig) -> ProviderRepository {
providers.add_rpc_provider::(BaseConfig::default());
providers.add_rpc_provider::(BinanceConfig::default());
+ providers.add_rpc_provider::(EtherlinkConfig::default());
providers.add_rpc_provider::(ZKSyncConfig::default());
providers.add_rpc_provider::(PublicnodeConfig::default());
providers.add_rpc_provider::(QuicknodeConfig::new(
diff --git a/src/providers/etherlink.rs b/src/providers/etherlink.rs
new file mode 100644
index 0000000000..b0d4afd706
--- /dev/null
+++ b/src/providers/etherlink.rs
@@ -0,0 +1,74 @@
+use {
+ super::{Provider, ProviderKind, RateLimited, RpcProvider, RpcProviderFactory},
+ crate::{
+ env::EtherlinkConfig,
+ error::{RpcError, RpcResult},
+ },
+ async_trait::async_trait,
+ axum::response::{IntoResponse, Response},
+ hyper::{client::HttpConnector, http, Client, Method},
+ hyper_tls::HttpsConnector,
+ std::collections::HashMap,
+ tracing::debug,
+};
+
+#[derive(Debug)]
+pub struct EtherlinkProvider {
+ pub client: Client>,
+ pub supported_chains: HashMap,
+}
+
+impl Provider for EtherlinkProvider {
+ fn supports_caip_chainid(&self, chain_id: &str) -> bool {
+ self.supported_chains.contains_key(chain_id)
+ }
+
+ fn supported_caip_chains(&self) -> Vec {
+ self.supported_chains.keys().cloned().collect()
+ }
+
+ fn provider_kind(&self) -> ProviderKind {
+ ProviderKind::Etherlink
+ }
+}
+
+#[async_trait]
+impl RateLimited for EtherlinkProvider {
+ async fn is_rate_limited(&self, response: &mut Response) -> bool {
+ response.status() == http::StatusCode::TOO_MANY_REQUESTS
+ }
+}
+
+#[async_trait]
+impl RpcProvider for EtherlinkProvider {
+ async fn proxy(&self, chain_id: &str, body: hyper::body::Bytes) -> RpcResult {
+ let uri = self
+ .supported_chains
+ .get(chain_id)
+ .ok_or(RpcError::ChainNotFound)?;
+
+ let hyper_request = hyper::http::Request::builder()
+ .method(Method::POST)
+ .uri(uri)
+ .header("Content-Type", "application/json")
+ .body(hyper::body::Body::from(body))?;
+
+ let response = self.client.request(hyper_request).await?.into_response();
+ }
+}
+
+impl RpcProviderFactory for EtherlinkProvider {
+ fn new(provider_config: &EtherlinkConfig) -> Self {
+ let forward_proxy_client = Client::builder().build::<_, hyper::Body>(HttpsConnector::new());
+ let supported_chains: HashMap = provider_config
+ .supported_chains
+ .iter()
+ .map(|(k, v)| (k.clone(), v.0.clone()))
+ .collect();
+
+ EtherlinkProvider {
+ client: forward_proxy_client,
+ supported_chains,
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/providers/mod.rs b/src/providers/mod.rs
index 2b891bddc7..30d648b09c 100644
--- a/src/providers/mod.rs
+++ b/src/providers/mod.rs
@@ -71,6 +71,7 @@ mod bungee;
mod coinbase;
mod drpc;
mod dune;
+mod etherlink;
mod getblock;
mod infura;
mod lava;
@@ -105,6 +106,7 @@ pub use {
bungee::BungeeProvider,
drpc::DrpcProvider,
dune::DuneProvider,
+ etherlink::EtherlinkProvider,
getblock::GetBlockProvider,
infura::{InfuraProvider, InfuraWsProvider},
lava::LavaProvider,
@@ -660,6 +662,7 @@ pub enum ProviderKind {
Binance,
Berachain,
Bungee,
+ Etherlink,
ZKSync,
Publicnode,
Base,
@@ -699,6 +702,7 @@ impl Display for ProviderKind {
ProviderKind::Berachain => "Berachain",
ProviderKind::Wemix => "Wemix",
ProviderKind::Bungee => "Bungee",
+ ProviderKind::Etherlink => "Etherlink",
ProviderKind::ZKSync => "zkSync",
ProviderKind::Publicnode => "Publicnode",
ProviderKind::Base => "Base",
@@ -737,6 +741,7 @@ impl ProviderKind {
"Binance" => Some(Self::Binance),
"Berachain" => Some(Self::Berachain),
"Bungee" => Some(Self::Bungee),
+ "Etherlink" => Some(Self::Etherlink),
"zkSync" => Some(Self::ZKSync),
"Publicnode" => Some(Self::Publicnode),
"Base" => Some(Self::Base),
diff --git a/tests/functional/http/etherlink.rs b/tests/functional/http/etherlink.rs
new file mode 100644
index 0000000000..8e06f7305e
--- /dev/null
+++ b/tests/functional/http/etherlink.rs
@@ -0,0 +1,28 @@
+use {
+ super::check_if_rpc_is_responding_correctly_for_supported_chain,
+ rpc_proxy::providers::ProviderKind,
+ crate::context::ServerContext,
+ test_context::test_context,
+};
+
+#[test_context(ServerContext)]
+#[tokio::test]
+#[ignore]
+async fn etherlink_provider_eip155_42793(ctx: &mut ServerContext) {
+ // Etherlink Mainnet
+ check_if_rpc_is_responding_correctly_for_supported_chain(
+ ctx,
+ &ProviderKind::Etherlink,
+ "eip155:42793",
+ "0xa729",
+ )
+ .await;
+
+ check_if_rpc_is_responding_correctly_for_supported_chain(
+ ctx,
+ &ProviderKind::Etherlink,
+ "eip155:128123",
+ "0x1f47b",
+ )
+ .await;
+}
\ No newline at end of file
diff --git a/tests/functional/http/mod.rs b/tests/functional/http/mod.rs
index e6f191bf80..c3a0d7bed5 100644
--- a/tests/functional/http/mod.rs
+++ b/tests/functional/http/mod.rs
@@ -11,6 +11,7 @@ pub(crate) mod aurora;
pub(crate) mod base;
pub(crate) mod berachain;
pub(crate) mod binance;
+pub(crate) mod etherlink;
pub(crate) mod drpc;
pub(crate) mod getblock;
pub(crate) mod infura;