From 5cb67503556274301ce70bc1070f28dcbbf12dbf Mon Sep 17 00:00:00 2001 From: zannis Date: Fri, 13 Mar 2026 16:01:36 +0200 Subject: [PATCH 1/2] feat: feature-gate signing providers (all enabled by default) --- crates/core/Cargo.toml | 37 +-- crates/core/src/lib.rs | 11 +- crates/core/src/provider/evm_provider.rs | 32 ++- crates/core/src/provider/mod.rs | 253 +++++++++--------- crates/core/src/startup.rs | 14 +- .../mnemonic_signing_key_providers/mod.rs | 7 + crates/core/src/wallet/mod.rs | 10 + crates/core/src/yaml.rs | 215 +++++++++------ .../rrelayer/docs/pages/changelog.mdx | 3 + 9 files changed, 332 insertions(+), 250 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 094b2b25..15b57b8f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -28,17 +28,17 @@ serde_json = { workspace = true } serde_yaml = "0.9.30" async-trait = "0.1" reqwest = { version = "0.12", features = ["json"] } -alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712", "signer-keystore", "signer-aws", "json-rpc"] } +alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712", "signer-keystore", "json-rpc"] } alloy-rlp = { workspace = true } alloy-eips = { workspace = true } uuid = { version = "1.0", features = ["v4", "serde"] } rand = "0.8" -aws-sdk-secretsmanager = "1.14.0" -aws-sdk-kms = "1.14.0" -aws-sdk-sts = "1.14.0" -aws-config = "1.1.4" +aws-sdk-secretsmanager = { version = "1.14.0", optional = true } +aws-sdk-kms = { version = "1.14.0", optional = true } +aws-sdk-sts = { version = "1.14.0", optional = true } +aws-config = { version = "1.1.4", optional = true } base64 = "0.22.0" -chrono = "0.4.19" +chrono = { version = "0.4.19", features = ["serde"] } bytes = "1.5.0" regex = "1.5.4" thiserror = "1.0" @@ -52,16 +52,21 @@ postgres-native-tls = "0.5" hex = "0.4.3" anyhow = "1.0.98" rust_decimal = { version = "1.35.0", features = ["db-tokio-postgres"] } -google-secretmanager1 = "6.0" -hyper = "0.14" -hyper-rustls = "0.24" +google-secretmanager1 = { version = "6.0", optional = true } rustls = { version = "0.23.35", features = ["ring"]} -hmac = "0.12" -sha2 = "0.10" -p256 = { version = "0.13", features = ["ecdsa"] } +sha2 = { version = "0.10", optional = true } +p256 = { version = "0.13", features = ["ecdsa"], optional = true } tower = "0.5.2" subtle = "2.6.1" -cryptoki = "0.10" -secrecy = "0.8" -jsonwebtoken = "9.3" -rsa = "0.9" +cryptoki = { version = "0.10", optional = true } +secrecy = { version = "0.8", optional = true } +jsonwebtoken = { version = "9.3", optional = true } + +[features] +default = ["gcp", "aws", "privy", "turnkey", "pkcs11", "fireblocks"] +gcp = ["dep:google-secretmanager1"] +aws = ["dep:aws-sdk-kms", "dep:aws-sdk-sts", "dep:aws-sdk-secretsmanager", "dep:aws-config", "alloy/signer-aws"] +privy = [] +turnkey = ["dep:p256"] +pkcs11 = ["dep:cryptoki", "dep:secrecy"] +fireblocks = ["dep:jsonwebtoken", "dep:sha2"] diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 4389fb49..1f614c6e 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -14,10 +14,11 @@ pub use provider::create_retry_client; pub mod relayer; pub mod safe_proxy; pub use safe_proxy::{SafeProxyError, SafeProxyManager, SafeTransaction}; +#[cfg(feature = "aws")] +pub use yaml::AwsKmsSigningProviderConfig; pub use yaml::{ - read, ApiConfig, AwsKmsSigningProviderConfig, GasProviders, NetworkSetupConfig, - RateLimitConfig, RateLimitWithInterval, RawSigningProviderConfig, SafeProxyConfig, SetupConfig, - SigningProvider, UserRateLimitConfig, + read, ApiConfig, GasProviders, NetworkSetupConfig, RateLimitConfig, RateLimitWithInterval, + RawSigningProviderConfig, SafeProxyConfig, SetupConfig, SigningProvider, UserRateLimitConfig, }; mod shared; pub use shared::{common_types, utils::get_chain_id}; @@ -30,7 +31,9 @@ mod schema; pub mod signing; pub mod transaction; mod wallet; -pub use wallet::{generate_seed_phrase, AwsKmsWalletManager, WalletError}; +#[cfg(feature = "aws")] +pub use wallet::AwsKmsWalletManager; +pub use wallet::{generate_seed_phrase, WalletError}; mod background_tasks; mod rate_limiting; pub use rate_limiting::RATE_LIMIT_HEADER_NAME; diff --git a/crates/core/src/provider/evm_provider.rs b/crates/core/src/provider/evm_provider.rs index 7036f38c..f7442bb2 100644 --- a/crates/core/src/provider/evm_provider.rs +++ b/crates/core/src/provider/evm_provider.rs @@ -1,15 +1,28 @@ use crate::gas::BLOB_GAS_PER_BLOB; use crate::provider::layer_extensions::RpcLoggingLayer; use crate::relayer::Relayer; +#[cfg(feature = "aws")] +use crate::wallet::AwsKmsWalletManager; +#[cfg(feature = "fireblocks")] +use crate::wallet::FireblocksWalletManager; +#[cfg(feature = "pkcs11")] +use crate::wallet::Pkcs11WalletManager; +#[cfg(feature = "privy")] +use crate::wallet::PrivyWalletManager; +#[cfg(feature = "turnkey")] +use crate::wallet::TurnkeyWalletManager; use crate::wallet::{ - AwsKmsWalletManager, CompositeWalletManager, FireblocksWalletManager, ImportKeyResult, - MnemonicWalletManager, Pkcs11WalletManager, PrivateKeyWalletManager, PrivyWalletManager, - TurnkeyWalletManager, WalletError, WalletManagerTrait, -}; -use crate::yaml::{ - AwsKmsSigningProviderConfig, FireblocksSigningProviderConfig, Pkcs11SigningProviderConfig, - TurnkeySigningProviderConfig, + CompositeWalletManager, ImportKeyResult, MnemonicWalletManager, PrivateKeyWalletManager, + WalletError, WalletManagerTrait, }; +#[cfg(feature = "aws")] +use crate::yaml::AwsKmsSigningProviderConfig; +#[cfg(feature = "fireblocks")] +use crate::yaml::FireblocksSigningProviderConfig; +#[cfg(feature = "pkcs11")] +use crate::yaml::Pkcs11SigningProviderConfig; +#[cfg(feature = "turnkey")] +use crate::yaml::TurnkeySigningProviderConfig; use crate::{ gas::{ BaseGasFeeEstimator, BlobGasEstimatorResult, BlobGasPriceResult, GasEstimatorError, @@ -168,6 +181,7 @@ impl EvmProvider { Self::new_internal(network_setup_config, wallet_manager, gas_estimator, true).await } + #[cfg(feature = "privy")] pub async fn new_with_privy( network_setup_config: &NetworkSetupConfig, app_id: String, @@ -179,6 +193,7 @@ impl EvmProvider { Self::new_internal(network_setup_config, wallet_manager, gas_estimator, true).await } + #[cfg(feature = "aws")] pub async fn new_with_aws_kms( network_setup_config: &NetworkSetupConfig, aws_kms_config: AwsKmsSigningProviderConfig, @@ -188,6 +203,7 @@ impl EvmProvider { Self::new_internal(network_setup_config, wallet_manager, gas_estimator, true).await } + #[cfg(feature = "turnkey")] pub async fn new_with_turnkey( network_setup_config: &NetworkSetupConfig, turnkey_config: TurnkeySigningProviderConfig, @@ -207,6 +223,7 @@ impl EvmProvider { Self::new_internal(network_setup_config, wallet_manager, gas_estimator, false).await } + #[cfg(feature = "pkcs11")] pub async fn new_with_pkcs11( network_setup_config: &NetworkSetupConfig, pkcs11_config: Pkcs11SigningProviderConfig, @@ -216,6 +233,7 @@ impl EvmProvider { Self::new_internal(network_setup_config, wallet_manager, gas_estimator, true).await } + #[cfg(feature = "fireblocks")] pub async fn new_with_fireblocks( network_setup_config: &NetworkSetupConfig, fireblocks_config: FireblocksSigningProviderConfig, diff --git a/crates/core/src/provider/mod.rs b/crates/core/src/provider/mod.rs index 3560b222..b7312c09 100644 --- a/crates/core/src/provider/mod.rs +++ b/crates/core/src/provider/mod.rs @@ -1,7 +1,20 @@ use std::path::Path; +use std::sync::Arc; use thiserror::Error; +use crate::wallet::get_mnemonic_from_signing_key; +#[cfg(feature = "aws")] +use crate::wallet::AwsKmsWalletManager; +#[cfg(feature = "fireblocks")] +use crate::wallet::FireblocksWalletManager; +use crate::wallet::MnemonicWalletManager; +#[cfg(feature = "pkcs11")] +use crate::wallet::Pkcs11WalletManager; +#[cfg(feature = "privy")] +use crate::wallet::PrivyWalletManager; +#[cfg(feature = "turnkey")] +use crate::wallet::TurnkeyWalletManager; use crate::{gas::get_gas_estimator, network::ChainId, SetupConfig, SigningProvider, WalletError}; mod evm_provider; @@ -9,7 +22,6 @@ mod layer_extensions; use self::evm_provider::EvmProviderNewError; use crate::gas::GasEstimatorError; -use crate::wallet::get_mnemonic_from_signing_key; pub use evm_provider::{ create_retry_client, EvmProvider, RelayerProvider, RetryClientError, SendTransactionError, }; @@ -62,158 +74,151 @@ pub async fn load_providers( .as_ref() .map(|private_keys| private_keys.iter().map(|pk| pk.raw.clone()).collect()); - // Check if we have a main signing provider (non-private-key) - let has_main_signing_provider = signing_key.privy.is_some() - || signing_key.aws_kms.is_some() - || signing_key.turnkey.is_some() - || signing_key.pkcs11.is_some() - || signing_key.fireblocks.is_some() - || signing_key.raw.is_some() - || signing_key.aws_secret_manager.is_some() - || signing_key.gcp_secret_manager.is_some(); + let has_main_signing_provider = signing_key.has_main_signing_provider(); + + let gas_estimator = get_gas_estimator(&config.provider_urls, setup_config, config).await?; // If we only have private keys and no main signing provider, use private key manager only if let Some(private_keys) = &private_key_strings { if !has_main_signing_provider { - let provider = EvmProvider::new_with_private_keys( - config, - private_keys.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await?; + let provider = + EvmProvider::new_with_private_keys(config, private_keys.clone(), gas_estimator) + .await?; providers.push(provider); continue; } } - let provider = if let Some(privy) = &signing_key.privy { - if private_key_strings.is_some() { - // Use composite manager with privy + private keys - let privy_manager = std::sync::Arc::new( - crate::wallet::PrivyWalletManager::new( + #[allow(unused_mut)] + let mut provider: Option = None; + + #[cfg(feature = "privy")] + if provider.is_none() { + if let Some(privy) = &signing_key.privy { + provider = Some(if private_key_strings.is_some() { + let privy_manager = Arc::new( + PrivyWalletManager::new(privy.app_id.clone(), privy.app_secret.clone()) + .await?, + ); + EvmProvider::new_with_composite( + config, + privy_manager, + private_key_strings.clone(), + gas_estimator.clone(), + ) + .await? + } else { + EvmProvider::new_with_privy( + config, privy.app_id.clone(), privy.app_secret.clone(), + gas_estimator.clone(), ) - .await?, - ); - EvmProvider::new_with_composite( - config, - privy_manager, - private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? - } else { - EvmProvider::new_with_privy( - config, - privy.app_id.clone(), - privy.app_secret.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + .await? + }); } - } else if let Some(aws_kms) = &signing_key.aws_kms { - if private_key_strings.is_some() { - // Use composite manager with aws_kms + private keys - let aws_manager = - std::sync::Arc::new(crate::wallet::AwsKmsWalletManager::new(aws_kms.clone())); - EvmProvider::new_with_composite( - config, - aws_manager, - private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? - } else { - EvmProvider::new_with_aws_kms( - config, - aws_kms.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + } + + #[cfg(feature = "aws")] + if provider.is_none() { + if let Some(aws_kms) = &signing_key.aws_kms { + provider = Some(if private_key_strings.is_some() { + let aws_manager = Arc::new(AwsKmsWalletManager::new(aws_kms.clone())); + EvmProvider::new_with_composite( + config, + aws_manager, + private_key_strings.clone(), + gas_estimator.clone(), + ) + .await? + } else { + EvmProvider::new_with_aws_kms(config, aws_kms.clone(), gas_estimator.clone()) + .await? + }); } - } else if let Some(turnkey) = &signing_key.turnkey { - if private_key_strings.is_some() { - // Use composite manager with turnkey + private keys - let turnkey_manager = std::sync::Arc::new( - crate::wallet::TurnkeyWalletManager::new(turnkey.clone()).await?, - ); - EvmProvider::new_with_composite( - config, - turnkey_manager, - private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? - } else { - EvmProvider::new_with_turnkey( - config, - turnkey.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + } + + #[cfg(feature = "turnkey")] + if provider.is_none() { + if let Some(turnkey) = &signing_key.turnkey { + provider = Some(if private_key_strings.is_some() { + let turnkey_manager = + Arc::new(TurnkeyWalletManager::new(turnkey.clone()).await?); + EvmProvider::new_with_composite( + config, + turnkey_manager, + private_key_strings.clone(), + gas_estimator.clone(), + ) + .await? + } else { + EvmProvider::new_with_turnkey(config, turnkey.clone(), gas_estimator.clone()) + .await? + }); } - } else if let Some(pkcs11) = &signing_key.pkcs11 { - if private_key_strings.is_some() { - let pkcs11_manager = - std::sync::Arc::new(crate::wallet::Pkcs11WalletManager::new(pkcs11.clone())?); - EvmProvider::new_with_composite( - config, - pkcs11_manager, - private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? - } else { - EvmProvider::new_with_pkcs11( - config, - pkcs11.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + } + + #[cfg(feature = "pkcs11")] + if provider.is_none() { + if let Some(pkcs11) = &signing_key.pkcs11 { + provider = Some(if private_key_strings.is_some() { + let pkcs11_manager = Arc::new(Pkcs11WalletManager::new(pkcs11.clone())?); + EvmProvider::new_with_composite( + config, + pkcs11_manager, + private_key_strings.clone(), + gas_estimator.clone(), + ) + .await? + } else { + EvmProvider::new_with_pkcs11(config, pkcs11.clone(), gas_estimator.clone()) + .await? + }); } - } else if let Some(fireblocks) = &signing_key.fireblocks { - if private_key_strings.is_some() { - let fireblocks_manager = std::sync::Arc::new( - crate::wallet::FireblocksWalletManager::new(fireblocks.clone()).await?, - ); - EvmProvider::new_with_composite( - config, - fireblocks_manager, - private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? - } else { - EvmProvider::new_with_fireblocks( - config, - fireblocks.clone(), - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + } + + #[cfg(feature = "fireblocks")] + if provider.is_none() { + if let Some(fireblocks) = &signing_key.fireblocks { + provider = Some(if private_key_strings.is_some() { + let fireblocks_manager = + Arc::new(FireblocksWalletManager::new(fireblocks.clone()).await?); + EvmProvider::new_with_composite( + config, + fireblocks_manager, + private_key_strings.clone(), + gas_estimator.clone(), + ) + .await? + } else { + EvmProvider::new_with_fireblocks( + config, + fireblocks.clone(), + gas_estimator.clone(), + ) + .await? + }); } + } + + // Fallback to mnemonic-based signing (raw, aws_secret_manager, gcp_secret_manager) + let provider = if let Some(p) = provider { + p } else { let mnemonic = get_mnemonic_from_signing_key(project_path, signing_key).await?; if private_key_strings.is_some() { - // Use composite manager with mnemonic + private keys - let mnemonic_manager = - std::sync::Arc::new(crate::wallet::MnemonicWalletManager::new(&mnemonic)); + let mnemonic_manager = Arc::new(MnemonicWalletManager::new(&mnemonic)); EvmProvider::new_with_composite( config, mnemonic_manager, private_key_strings, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, + gas_estimator, ) .await? } else { - EvmProvider::new_with_mnemonic( - config, - &mnemonic, - get_gas_estimator(&config.provider_urls, setup_config, config).await?, - ) - .await? + EvmProvider::new_with_mnemonic(config, &mnemonic, gas_estimator).await? } }; diff --git a/crates/core/src/startup.rs b/crates/core/src/startup.rs index 1efcc8ab..e6e07a3e 100644 --- a/crates/core/src/startup.rs +++ b/crates/core/src/startup.rs @@ -191,16 +191,10 @@ async fn start_api( }; // Check if only private keys are configured - if signing_provider.private_keys.is_some() - && signing_provider.raw.is_none() - && signing_provider.aws_secret_manager.is_none() - && signing_provider.gcp_secret_manager.is_none() - && signing_provider.privy.is_none() - && signing_provider.aws_kms.is_none() - && signing_provider.turnkey.is_none() - && signing_provider.pkcs11.is_none() - && signing_provider.fireblocks.is_none() - { + let is_private_key_only = signing_provider.private_keys.is_some() + && !signing_provider.has_main_signing_provider(); + + if is_private_key_only { Some(network_config.chain_id) } else { None diff --git a/crates/core/src/wallet/mnemonic_signing_key_providers/mod.rs b/crates/core/src/wallet/mnemonic_signing_key_providers/mod.rs index 537f83dd..29cca8fe 100644 --- a/crates/core/src/wallet/mnemonic_signing_key_providers/mod.rs +++ b/crates/core/src/wallet/mnemonic_signing_key_providers/mod.rs @@ -2,11 +2,16 @@ use crate::wallet::WalletError; use crate::SigningProvider; use std::path::Path; +#[cfg(feature = "aws")] mod aws_secret_manager; +#[cfg(feature = "aws")] use aws_secret_manager::get_aws_secret; +#[cfg(feature = "gcp")] mod gcp_secret_manager; +#[cfg(feature = "gcp")] use gcp_secret_manager::get_gcp_secret; +#[allow(unused_variables)] pub async fn get_mnemonic_from_signing_key( project_path: &Path, signing_key: &SigningProvider, @@ -15,11 +20,13 @@ pub async fn get_mnemonic_from_signing_key( return Ok(raw.mnemonic.clone()); } + #[cfg(feature = "aws")] if let Some(aws_secret_manager) = &signing_key.aws_secret_manager { let result = get_aws_secret(aws_secret_manager).await?; return Ok(result); } + #[cfg(feature = "gcp")] if let Some(gcp_secret_manager) = &signing_key.gcp_secret_manager { let result = get_gcp_secret(project_path, gcp_secret_manager).await?; return Ok(result); diff --git a/crates/core/src/wallet/mod.rs b/crates/core/src/wallet/mod.rs index 43b8162d..3f35a56d 100644 --- a/crates/core/src/wallet/mod.rs +++ b/crates/core/src/wallet/mod.rs @@ -12,22 +12,32 @@ pub use mnemonic_wallet_manager::{generate_seed_phrase, MnemonicWalletManager}; mod mnemonic_signing_key_providers; pub use mnemonic_signing_key_providers::get_mnemonic_from_signing_key; +#[cfg(feature = "aws")] mod aws_kms_wallet_manager; +#[cfg(feature = "aws")] pub use aws_kms_wallet_manager::AwsKmsWalletManager; +#[cfg(feature = "privy")] mod privy_wallet_manager; +#[cfg(feature = "privy")] pub use privy_wallet_manager::PrivyWalletManager; +#[cfg(feature = "turnkey")] mod turnkey_wallet_manager; +#[cfg(feature = "turnkey")] pub use turnkey_wallet_manager::TurnkeyWalletManager; mod private_key_wallet_manager; pub use private_key_wallet_manager::PrivateKeyWalletManager; +#[cfg(feature = "pkcs11")] mod pkcs11_wallet_manager; +#[cfg(feature = "pkcs11")] pub use pkcs11_wallet_manager::Pkcs11WalletManager; +#[cfg(feature = "fireblocks")] mod fireblocks_wallet_manager; +#[cfg(feature = "fireblocks")] pub use fireblocks_wallet_manager::FireblocksWalletManager; mod composite_wallet_manager; diff --git a/crates/core/src/yaml.rs b/crates/core/src/yaml.rs index 5613a514..93195473 100644 --- a/crates/core/src/yaml.rs +++ b/crates/core/src/yaml.rs @@ -16,6 +16,7 @@ use crate::shared::utils::format_token_amount; use crate::transaction::types::TransactionSpeed; use crate::{rrelayer_error, shared::common_types::EvmAddress}; +#[cfg(feature = "gcp")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct GcpSecretManagerProviderConfig { pub id: String, @@ -25,6 +26,7 @@ pub struct GcpSecretManagerProviderConfig { pub service_account_key_path: String, } +#[cfg(feature = "aws")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct AwsSecretManagerProviderConfig { pub id: String, @@ -32,6 +34,7 @@ pub struct AwsSecretManagerProviderConfig { pub region: String, } +#[cfg(feature = "aws")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct AwsKmsSigningProviderConfig { pub region: String, @@ -47,12 +50,14 @@ pub struct RawSigningProviderConfig { pub mnemonic: String, } +#[cfg(feature = "privy")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct PrivySigningProviderConfig { pub app_id: String, pub app_secret: String, } +#[cfg(feature = "turnkey")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct TurnkeySigningProviderConfig { pub api_public_key: String, @@ -61,6 +66,7 @@ pub struct TurnkeySigningProviderConfig { pub wallet_id: String, } +#[cfg(feature = "pkcs11")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Pkcs11SigningProviderConfig { pub library_path: String, @@ -75,6 +81,7 @@ pub struct Pkcs11SigningProviderConfig { pub test_mode: Option, } +#[cfg(feature = "fireblocks")] #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FireblocksSigningProviderConfig { pub api_key: String, @@ -92,29 +99,36 @@ pub struct PrivateKeyConfig { pub raw: String, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct SigningProvider { #[serde(skip_serializing_if = "Option::is_none", default)] pub raw: Option, + #[cfg(feature = "aws")] #[serde(skip_serializing_if = "Option::is_none", default)] pub aws_secret_manager: Option, + #[cfg(feature = "gcp")] #[serde(skip_serializing_if = "Option::is_none", default)] pub gcp_secret_manager: Option, + #[cfg(feature = "privy")] #[serde(skip_serializing_if = "Option::is_none", default)] pub privy: Option, + #[cfg(feature = "aws")] #[serde(skip_serializing_if = "Option::is_none", default)] pub aws_kms: Option, + #[cfg(feature = "turnkey")] #[serde(skip_serializing_if = "Option::is_none", default)] pub turnkey: Option, + #[cfg(feature = "pkcs11")] #[serde(skip_serializing_if = "Option::is_none", default)] pub pkcs11: Option, + #[cfg(feature = "fireblocks")] #[serde(skip_serializing_if = "Option::is_none", default)] pub fireblocks: Option, @@ -147,6 +161,7 @@ pub struct RateLimitConfig { pub fallback_to_relayer: bool, } +#[cfg(feature = "aws")] impl AwsKmsSigningProviderConfig { pub fn validate(&self) -> Result<(), String> { if self.region.is_empty() { @@ -156,6 +171,7 @@ impl AwsKmsSigningProviderConfig { } } +#[cfg(feature = "turnkey")] impl TurnkeySigningProviderConfig { pub fn validate(&self) -> Result<(), String> { if self.api_public_key.is_empty() { @@ -174,6 +190,7 @@ impl TurnkeySigningProviderConfig { } } +#[cfg(feature = "fireblocks")] impl FireblocksSigningProviderConfig { pub fn validate(&self) -> Result<(), String> { if self.api_key.is_empty() { @@ -226,8 +243,23 @@ impl FireblocksSigningProviderConfig { Ok(()) } + + /// Returns the appropriate base URL based on sandbox setting + pub fn get_base_url(&self) -> String { + if self.sandbox.unwrap_or(false) { + "https://sandbox-api.fireblocks.io".to_string() + } else { + "https://api.fireblocks.io".to_string() + } + } + + /// Returns true if running in sandbox mode + pub fn is_sandbox(&self) -> bool { + self.sandbox.unwrap_or(false) + } } +#[cfg(feature = "pkcs11")] impl Pkcs11SigningProviderConfig { pub fn validate(&self) -> Result<(), String> { if self.library_path.is_empty() { @@ -257,112 +289,113 @@ impl Pkcs11SigningProviderConfig { } } -impl FireblocksSigningProviderConfig { - /// Returns the appropriate base URL based on sandbox setting - pub fn get_base_url(&self) -> String { - if self.sandbox.unwrap_or(false) { - // Use sandbox environment - "https://sandbox-api.fireblocks.io".to_string() - } else { - // Use production environment (default) - "https://api.fireblocks.io".to_string() - } - } - - /// Returns true if running in sandbox mode - pub fn is_sandbox(&self) -> bool { - self.sandbox.unwrap_or(false) - } -} - impl SigningProvider { pub fn from_raw(raw: RawSigningProviderConfig) -> Self { - Self { - raw: Some(raw), - aws_secret_manager: None, - gcp_secret_manager: None, - privy: None, - aws_kms: None, - turnkey: None, - pkcs11: None, - fireblocks: None, - private_keys: None, - } + Self { raw: Some(raw), ..Default::default() } } + #[cfg(feature = "aws")] pub fn from_aws_kms(aws_kms: AwsKmsSigningProviderConfig) -> Self { - Self { - raw: None, - aws_secret_manager: None, - gcp_secret_manager: None, - privy: None, - aws_kms: Some(aws_kms), - turnkey: None, - pkcs11: None, - fireblocks: None, - private_keys: None, - } + Self { aws_kms: Some(aws_kms), ..Default::default() } } + #[cfg(feature = "turnkey")] pub fn from_turnkey(turnkey: TurnkeySigningProviderConfig) -> Self { - Self { - raw: None, - aws_secret_manager: None, - gcp_secret_manager: None, - privy: None, - aws_kms: None, - turnkey: Some(turnkey), - pkcs11: None, - fireblocks: None, - private_keys: None, - } + Self { turnkey: Some(turnkey), ..Default::default() } } + #[cfg(feature = "pkcs11")] pub fn from_pkcs11(pkcs11: Pkcs11SigningProviderConfig) -> Self { - Self { - raw: None, - aws_secret_manager: None, - gcp_secret_manager: None, - privy: None, - aws_kms: None, - turnkey: None, - pkcs11: Some(pkcs11), - fireblocks: None, - private_keys: None, - } + Self { pkcs11: Some(pkcs11), ..Default::default() } } + #[cfg(feature = "fireblocks")] pub fn from_fireblocks(fireblocks: FireblocksSigningProviderConfig) -> Self { - Self { - raw: None, - aws_secret_manager: None, - gcp_secret_manager: None, - privy: None, - aws_kms: None, - turnkey: None, - pkcs11: None, - fireblocks: Some(fireblocks), - private_keys: None, + Self { fireblocks: Some(fireblocks), ..Default::default() } + } + + /// Returns true if any main signing provider (non-private-key) is configured. + pub fn has_main_signing_provider(&self) -> bool { + #[allow(unused_mut)] + let mut result = self.raw.is_some(); + + #[cfg(feature = "aws")] + { + result = result || self.aws_kms.is_some() || self.aws_secret_manager.is_some(); + } + + #[cfg(feature = "gcp")] + if self.gcp_secret_manager.is_some() { + result = true; + } + + #[cfg(feature = "privy")] + if self.privy.is_some() { + result = true; + } + + #[cfg(feature = "turnkey")] + if self.turnkey.is_some() { + result = true; + } + + #[cfg(feature = "pkcs11")] + if self.pkcs11.is_some() { + result = true; } + + #[cfg(feature = "fireblocks")] + if self.fireblocks.is_some() { + result = true; + } + + result } -} -impl SigningProvider { pub fn validate(&self) -> Result<(), String> { - let configured_methods = [ - self.raw.is_some(), - self.aws_secret_manager.is_some(), - self.gcp_secret_manager.is_some(), - self.privy.is_some(), - self.aws_kms.is_some(), - self.turnkey.is_some(), - self.pkcs11.is_some(), - self.fireblocks.is_some(), - self.private_keys.is_some(), - ] - .iter() - .filter(|&&x| x) - .count(); + let mut configured_methods = 0usize; + + if self.raw.is_some() { + configured_methods += 1; + } + if self.private_keys.is_some() { + configured_methods += 1; + } + + #[cfg(feature = "aws")] + { + if self.aws_secret_manager.is_some() { + configured_methods += 1; + } + if self.aws_kms.is_some() { + configured_methods += 1; + } + } + + #[cfg(feature = "gcp")] + if self.gcp_secret_manager.is_some() { + configured_methods += 1; + } + + #[cfg(feature = "privy")] + if self.privy.is_some() { + configured_methods += 1; + } + + #[cfg(feature = "turnkey")] + if self.turnkey.is_some() { + configured_methods += 1; + } + + #[cfg(feature = "pkcs11")] + if self.pkcs11.is_some() { + configured_methods += 1; + } + + #[cfg(feature = "fireblocks")] + if self.fireblocks.is_some() { + configured_methods += 1; + } match configured_methods { 0 => Err("Signing key is not set".to_string()), @@ -999,18 +1032,22 @@ pub fn read(file_path: &PathBuf, raw_yaml: bool) -> Result Date: Fri, 13 Mar 2026 16:14:09 +0200 Subject: [PATCH 2/2] import rrelayer_core without default features on the client --- crates/sdk/Cargo.toml | 2 +- documentation/rrelayer/docs/pages/changelog.mdx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 5ea9f5fd..b5e9a2d3 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -26,7 +26,7 @@ anyhow = { workspace = true } thiserror = "2.0.6" alloy = { workspace = true, features = ["full", "signer-mnemonic", "eips", "eip712"] } base64 = "0.22.0" -rrelayer_core = { path = "../core" } +rrelayer_core = { path = "../core", default-features = false } tokio = { version = "1", features = ["time"] } async-trait = "0.1" hex = "0.4" diff --git a/documentation/rrelayer/docs/pages/changelog.mdx b/documentation/rrelayer/docs/pages/changelog.mdx index 60b11ecd..fdfaced6 100644 --- a/documentation/rrelayer/docs/pages/changelog.mdx +++ b/documentation/rrelayer/docs/pages/changelog.mdx @@ -7,6 +7,7 @@ ### Features - feat: all third-party signing provider integrations are now behind cargo feature flags (all enabled by default). Available features: `gcp`, `aws`, `privy`, `turnkey`, `pkcs11`, `fireblocks`. Disable unneeded providers with `--no-default-features` to reduce compile time and binary size. +- feat: the Rust SDK (`rrelayer` crate) no longer pulls in signing provider dependencies from `rrelayer_core` by default, reducing dependency footprint for SDK consumers. - chore: removed unused `hmac` and `rsa` dependencies. ---