diff --git a/crates/node/src/config/foreign_chains/auth.rs b/crates/node/src/config/foreign_chains/auth.rs index 4b926ab94..ea56a0fd7 100644 --- a/crates/node/src/config/foreign_chains/auth.rs +++ b/crates/node/src/config/foreign_chains/auth.rs @@ -40,6 +40,20 @@ impl AuthConfig { _ => Cow::Borrowed(rpc_url), } } + + /// Returns the RPC URL with the `Path` auth placeholder substituted with the resolved token. + /// + /// For `Path` auth, replaces the placeholder string in the URL with the resolved token value. + /// For all other auth kinds, returns the original URL unchanged. + pub(crate) fn resolve_url(&self, rpc_url: &str) -> anyhow::Result { + match self { + AuthConfig::Path { placeholder, token } => { + let token_value = token.resolve()?; + Ok(rpc_url.replace(placeholder.as_str(), &token_value)) + } + _ => Ok(rpc_url.to_string()), + } + } } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -188,4 +202,52 @@ mod tests { assert_matches!(result, Cow::Owned(_)); assert_eq!(result, "https://rpc.ankr.com/near/"); } + + #[test] + fn resolve_url__returns_original_for_none_auth() { + let auth = AuthConfig::None; + let url = "https://rpc.example.com"; + let result = auth.resolve_url(url).unwrap(); + assert_eq!(result, url); + } + + #[test] + fn resolve_url__returns_original_for_header_auth() { + let auth = AuthConfig::Header { + name: http::HeaderName::from_static("authorization"), + scheme: Some("Bearer".to_string()), + token: TokenConfig::Val { + val: "secret".to_string(), + }, + }; + let url = "https://rpc.example.com/v2/"; + let result = auth.resolve_url(url).unwrap(); + assert_eq!(result, url); + } + + #[test] + fn resolve_url__substitutes_placeholder_for_path_auth() { + let auth = AuthConfig::Path { + placeholder: "{api_key}".to_string(), + token: TokenConfig::Val { + val: "my-secret-key".to_string(), + }, + }; + let url = "https://abstract-mainnet.g.alchemy.com/v2/{api_key}"; + let result = auth.resolve_url(url).unwrap(); + assert_eq!(result, "https://abstract-mainnet.g.alchemy.com/v2/my-secret-key"); + } + + #[test] + fn resolve_url__returns_original_for_query_auth() { + let auth = AuthConfig::Query { + name: "api_key".to_string(), + token: TokenConfig::Val { + val: "secret".to_string(), + }, + }; + let url = "https://rpc.example.com"; + let result = auth.resolve_url(url).unwrap(); + assert_eq!(result, url); + } } diff --git a/crates/node/src/providers/verify_foreign_tx/sign.rs b/crates/node/src/providers/verify_foreign_tx/sign.rs index 198731e9b..c50997182 100644 --- a/crates/node/src/providers/verify_foreign_tx/sign.rs +++ b/crates/node/src/providers/verify_foreign_tx/sign.rs @@ -168,7 +168,9 @@ where anyhow::bail!("found empty list of providers for bitcoin") }; - let public_node_url = bitcoin_provider_config.rpc_url.clone(); + let public_node_url = bitcoin_provider_config + .auth + .resolve_url(&bitcoin_provider_config.rpc_url)?; let http_client = foreign_chain_inspector::build_http_client( public_node_url, @@ -211,7 +213,9 @@ where anyhow::bail!("found empty list of providers for abstract") }; - let public_node_url = abstract_provider_config.rpc_url.clone(); + let public_node_url = abstract_provider_config + .auth + .resolve_url(&abstract_provider_config.rpc_url)?; let http_client = foreign_chain_inspector::build_http_client( public_node_url, @@ -254,7 +258,9 @@ where anyhow::bail!("found empty list of providers for starknet") }; - let rpc_url = starknet_provider_config.rpc_url.clone(); + let rpc_url = starknet_provider_config + .auth + .resolve_url(&starknet_provider_config.rpc_url)?; let http_client = foreign_chain_inspector::build_http_client( rpc_url,