Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions crates/node/src/config/foreign_chains/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> {
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)]
Expand Down Expand Up @@ -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);
}
}
12 changes: 9 additions & 3 deletions crates/node/src/providers/verify_foreign_tx/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down