diff --git a/bin/builder.rs b/bin/builder.rs
index a6a2f33..86cd191 100644
--- a/bin/builder.rs
+++ b/bin/builder.rs
@@ -6,7 +6,7 @@ use builder::{
         tx_poller,
     },
 };
-use init4_bin_base::{deps::tracing, utils::calc::SlotCalculator};
+use init4_bin_base::{deps::tracing, utils::from_env::FromEnv};
 use signet_sim::SimCache;
 use std::sync::Arc;
 use tokio::select;
@@ -19,15 +19,13 @@ async fn main() -> eyre::Result<()> {
     let _guard = init4_bin_base::init4();
     let init_span_guard = info_span!("builder initialization");
 
-    let config = BuilderConfig::load_from_env()?.clone();
+    let config = BuilderConfig::from_env()?.clone();
     let constants = config.load_pecorino_constants();
     let authenticator = Authenticator::new(&config)?;
 
-    let (host_provider, ru_provider, sequencer_signer) = tokio::try_join!(
-        config.connect_host_provider(),
-        config.connect_ru_provider(),
-        config.connect_sequencer_signer(),
-    )?;
+    let (host_provider, sequencer_signer) =
+        tokio::try_join!(config.connect_host_provider(), config.connect_sequencer_signer(),)?;
+    let ru_provider = config.connect_ru_provider();
 
     let zenith = config.connect_zenith(host_provider.clone());
 
@@ -55,8 +53,7 @@ async fn main() -> eyre::Result<()> {
     let (submit_channel, submit_jh) = submit.spawn();
 
     let sim_items = SimCache::new();
-    let slot_calculator =
-        SlotCalculator::new(config.start_timestamp, config.chain_offset, config.target_slot_time);
+    let slot_calculator = config.slot_calculator;
 
     let sim = Arc::new(Simulator::new(&config, ru_provider.clone(), slot_calculator));
 
diff --git a/bin/submit_transaction.rs b/bin/submit_transaction.rs
index 6aec853..55e2dbe 100644
--- a/bin/submit_transaction.rs
+++ b/bin/submit_transaction.rs
@@ -5,32 +5,65 @@ use alloy::{
     rpc::types::eth::TransactionRequest,
     signers::aws::AwsSigner,
 };
-use aws_config::BehaviorVersion;
-use builder::config::{HostProvider, load_address, load_string, load_u64, load_url};
+use builder::config::HostProvider;
 use init4_bin_base::{
     deps::metrics::{counter, histogram},
     init4,
+    utils::from_env::FromEnv,
 };
 use std::time::{Duration, Instant};
 use tokio::time::timeout;
 
+#[derive(Debug, Clone, FromEnv)]
+struct Config {
+    #[from_env(var = "RPC_URL", desc = "Ethereum RPC URL")]
+    rpc_url: String,
+    #[from_env(var = "CHAIN_ID", desc = "Ethereum chain ID")]
+    chain_id: u64,
+    #[from_env(var = "AWS_KMS_KEY_ID", desc = "AWS KMS key ID")]
+    kms_key_id: String,
+    #[from_env(var = "RECIPIENT_ADDRESS", desc = "Recipient address")]
+    recipient_address: Address,
+    #[from_env(var = "SLEEP_TIME", desc = "Time to sleep between transactions")]
+    sleep_time: u64,
+}
+
+impl Config {
+    async fn provider(&self) -> HostProvider {
+        let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
+        let client = aws_sdk_kms::Client::new(&config);
+        let signer =
+            AwsSigner::new(client, self.kms_key_id.clone(), Some(self.chain_id)).await.unwrap();
+
+        ProviderBuilder::new()
+            .wallet(EthereumWallet::from(signer))
+            .connect(&self.rpc_url)
+            .await
+            .unwrap()
+    }
+}
+
 #[tokio::main]
 async fn main() {
     init4();
 
     tracing::trace!("connecting to provider");
-    let (provider, recipient_address, sleep_time) = connect_from_config().await;
+
+    let config = Config::from_env().unwrap();
+    let provider = config.provider().await;
+    let recipient_address = config.recipient_address;
+    let sleep_time = config.sleep_time;
 
     loop {
         tracing::debug!("attempting transaction");
-        send_transaction(provider.clone(), recipient_address).await;
+        send_transaction(&provider, recipient_address).await;
 
         tracing::debug!(sleep_time, "sleeping");
         tokio::time::sleep(tokio::time::Duration::from_secs(sleep_time)).await;
     }
 }
 
-async fn send_transaction(provider: HostProvider, recipient_address: Address) {
+async fn send_transaction(provider: &HostProvider, recipient_address: Address) {
     // construct simple transaction to send ETH to a recipient
     let tx = TransactionRequest::default()
         .with_from(provider.default_signer_address())
@@ -66,26 +99,3 @@ async fn send_transaction(provider: HostProvider, recipient_address: Address) {
     tracing::debug!(success = receipt.status(), mine_time, hash, "transaction mined");
     histogram!("txn_submitter.tx_mine_time").record(mine_time as f64);
 }
-
-async fn connect_from_config() -> (HostProvider, Address, u64) {
-    // load signer config values from .env
-    let rpc_url = load_url("RPC_URL").unwrap();
-    let chain_id = load_u64("CHAIN_ID").unwrap();
-    let kms_key_id = load_string("AWS_KMS_KEY_ID").unwrap();
-    // load transaction sending config value from .env
-    let recipient_address: Address = load_address("RECIPIENT_ADDRESS").unwrap();
-    let sleep_time = load_u64("SLEEP_TIME").unwrap();
-
-    // connect signer & provider
-    let config = aws_config::load_defaults(BehaviorVersion::latest()).await;
-    let client = aws_sdk_kms::Client::new(&config);
-    let signer = AwsSigner::new(client, kms_key_id.to_string(), Some(chain_id)).await.unwrap();
-
-    let provider = ProviderBuilder::new()
-        .wallet(EthereumWallet::from(signer))
-        .connect(&rpc_url)
-        .await
-        .unwrap();
-
-    (provider, recipient_address, sleep_time)
-}
diff --git a/src/config.rs b/src/config.rs
index b442212..3a1a6a9 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -14,144 +14,147 @@ use alloy::{
     },
 };
 use eyre::Result;
+use init4_bin_base::utils::{calc::SlotCalculator, from_env::FromEnv};
 use oauth2::url;
 use signet_types::config::{HostConfig, PredeployTokens, RollupConfig, SignetSystemConstants};
 use signet_zenith::Zenith;
-use std::{borrow::Cow, env, num, str::FromStr};
+use std::borrow::Cow;
 
-// Keys for .env variables that need to be set to configure the builder.
-const HOST_CHAIN_ID: &str = "HOST_CHAIN_ID";
-const RU_CHAIN_ID: &str = "RU_CHAIN_ID";
-const HOST_RPC_URL: &str = "HOST_RPC_URL";
-const ROLLUP_RPC_URL: &str = "ROLLUP_RPC_URL";
-const TX_BROADCAST_URLS: &str = "TX_BROADCAST_URLS";
-const ZENITH_ADDRESS: &str = "ZENITH_ADDRESS";
-const BUILDER_HELPER_ADDRESS: &str = "BUILDER_HELPER_ADDRESS";
-const QUINCEY_URL: &str = "QUINCEY_URL";
-const BUILDER_PORT: &str = "BUILDER_PORT";
-const SEQUENCER_KEY: &str = "SEQUENCER_KEY"; // empty (to use Quincey) OR AWS key ID (to use AWS signer) OR raw private key (to use local signer)
-const BUILDER_KEY: &str = "BUILDER_KEY"; // AWS key ID (to use AWS signer) OR raw private key (to use local signer)
-const BLOCK_CONFIRMATION_BUFFER: &str = "BLOCK_CONFIRMATION_BUFFER";
-const CHAIN_OFFSET: &str = "CHAIN_OFFSET";
-const TARGET_SLOT_TIME: &str = "TARGET_SLOT_TIME";
-const BUILDER_REWARDS_ADDRESS: &str = "BUILDER_REWARDS_ADDRESS";
-const ROLLUP_BLOCK_GAS_LIMIT: &str = "ROLLUP_BLOCK_GAS_LIMIT";
-const TX_POOL_URL: &str = "TX_POOL_URL";
-const AUTH_TOKEN_REFRESH_INTERVAL: &str = "AUTH_TOKEN_REFRESH_INTERVAL";
-const TX_POOL_CACHE_DURATION: &str = "TX_POOL_CACHE_DURATION";
-const OAUTH_CLIENT_ID: &str = "OAUTH_CLIENT_ID";
-const OAUTH_CLIENT_SECRET: &str = "OAUTH_CLIENT_SECRET";
-const OAUTH_AUTHENTICATE_URL: &str = "OAUTH_AUTHENTICATE_URL";
-const OAUTH_TOKEN_URL: &str = "OAUTH_TOKEN_URL";
-const CONCURRENCY_LIMIT: &str = "CONCURRENCY_LIMIT";
-const START_TIMESTAMP: &str = "START_TIMESTAMP";
+/// Type alias for the provider used to build and submit blocks to the host.
+pub type HostProvider = FillProvider<
+    JoinFill<
+        JoinFill<
+            Identity,
+            JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
+        >,
+        WalletFiller<EthereumWallet>,
+    >,
+    RootProvider,
+    Ethereum,
+>;
 
 /// Configuration for a builder running a specific rollup on a specific host
 /// chain.
-#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+#[derive(serde::Deserialize, Debug, Clone, FromEnv)]
 pub struct BuilderConfig {
     /// The chain ID of the host chain
+    #[from_env(var = "HOST_CHAIN_ID", desc = "The chain ID of the host chain")]
     pub host_chain_id: u64,
-    /// The chain ID of the host chain
+    /// The chain ID of the rollup chain
+    #[from_env(var = "RU_CHAIN_ID", desc = "The chain ID of the rollup chain")]
     pub ru_chain_id: u64,
     /// URL for Host RPC node.
+    #[from_env(var = "HOST_RPC_URL", desc = "URL for Host RPC node", infallible)]
     pub host_rpc_url: Cow<'static, str>,
     /// URL for the Rollup RPC node.
+    #[from_env(var = "ROLLUP_RPC_URL", desc = "URL for Rollup RPC node", infallible)]
     pub ru_rpc_url: Cow<'static, str>,
     /// Additional RPC URLs to which to broadcast transactions.
     /// NOTE: should not include the host_rpc_url value
+    #[from_env(
+        var = "TX_BROADCAST_URLS",
+        desc = "Additional RPC URLs to which to broadcast transactions",
+        infallible
+    )]
     pub tx_broadcast_urls: Vec<Cow<'static, str>>,
     /// address of the Zenith contract on Host.
+    #[from_env(var = "ZENITH_ADDRESS", desc = "address of the Zenith contract on Host")]
     pub zenith_address: Address,
     /// address of the Builder Helper contract on Host.
+    #[from_env(
+        var = "BUILDER_HELPER_ADDRESS",
+        desc = "address of the Builder Helper contract on Host"
+    )]
     pub builder_helper_address: Address,
     /// URL for remote Quincey Sequencer server to sign blocks.
     /// Disregarded if a sequencer_signer is configured.
+    #[from_env(
+        var = "QUINCEY_URL",
+        desc = "URL for remote Quincey Sequencer server to sign blocks",
+        infallible
+    )]
     pub quincey_url: Cow<'static, str>,
     /// Port for the Builder server.
+    #[from_env(var = "BUILDER_PORT", desc = "Port for the Builder server")]
     pub builder_port: u16,
     /// Key to access Sequencer Wallet - AWS Key ID _OR_ local private key.
     /// Set IFF using local Sequencer signing instead of remote Quincey signing.
+    #[from_env(
+        var = "SEQUENCER_KEY",
+        desc = "Key to access Sequencer Wallet - AWS Key ID _OR_ local private key, set IFF using local Sequencer signing instead of remote Quincey signing",
+        infallible,
+        optional
+    )]
     pub sequencer_key: Option<String>,
     /// Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key.
+    #[from_env(
+        var = "BUILDER_KEY",
+        desc = "Key to access Builder transaction submission wallet - AWS Key ID _OR_ local private key",
+        infallible
+    )]
     pub builder_key: String,
     /// Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain.
+    #[from_env(
+        var = "BLOCK_CONFIRMATION_BUFFER",
+        desc = "Buffer in seconds in which the `submitBlock` transaction must confirm on the Host chain"
+    )]
     pub block_confirmation_buffer: u64,
-    /// The offset between Unix time and the chain's block times. For Holesky, this is 0; for Ethereum, 11.
-    pub chain_offset: u64,
-    /// The slot time at which the Builder should begin building a block. 0 to begin at the very start of the slot; 6 to begin in the middle; etc.
-    pub target_slot_time: u64,
+
     /// Address on Rollup to which Builder will receive user transaction fees.
+    #[from_env(
+        var = "BUILDER_REWARDS_ADDRESS",
+        desc = "Address on Rollup to which Builder will receive user transaction fees"
+    )]
     pub builder_rewards_address: Address,
     /// Gas limit for RU block.
     /// NOTE: a "smart" builder would determine this programmatically by simulating the block.
+    #[from_env(var = "ROLLUP_BLOCK_GAS_LIMIT", desc = "Gas limit for RU block")]
     pub rollup_block_gas_limit: u64,
     /// URL of the tx pool to poll for incoming transactions.
+    #[from_env(
+        var = "TX_POOL_URL",
+        desc = "URL of the tx pool to poll for incoming transactions",
+        infallible
+    )]
     pub tx_pool_url: Cow<'static, str>,
     /// Duration in seconds transactions can live in the tx-pool cache.
+    #[from_env(
+        var = "TX_POOL_CACHE_DURATION",
+        desc = "Duration in seconds transactions can live in the tx-pool cache"
+    )]
     pub tx_pool_cache_duration: u64,
     /// OAuth client ID for the builder.
+    #[from_env(var = "OAUTH_CLIENT_ID", desc = "OAuth client ID for the builder")]
     pub oauth_client_id: String,
     /// OAuth client secret for the builder.
+    #[from_env(var = "OAUTH_CLIENT_SECRET", desc = "OAuth client secret for the builder")]
     pub oauth_client_secret: String,
     /// OAuth authenticate URL for the builder for performing OAuth logins.
+    #[from_env(
+        var = "OAUTH_AUTHENTICATE_URL",
+        desc = "OAuth authenticate URL for the builder for performing OAuth logins"
+    )]
     pub oauth_authenticate_url: String,
     /// OAuth token URL for the builder to get an OAuth2 access token
+    #[from_env(
+        var = "OAUTH_TOKEN_URL",
+        desc = "OAuth token URL for the builder to get an OAuth2 access token"
+    )]
     pub oauth_token_url: String,
     /// The oauth token refresh interval in seconds.
+    #[from_env(var = "CONCURRENCY_LIMIT", desc = "The oauth token refresh interval in seconds")]
     pub oauth_token_refresh_interval: u64,
     /// The max number of simultaneous block simulations to run.
+    #[from_env(
+        var = "CONCURRENCY_LIMIT",
+        desc = "The max number of simultaneous block simulations to run"
+    )]
     pub concurrency_limit: usize,
-    /// The anchor for slot time and number calculations before adjusting for chain offset.
-    pub start_timestamp: u64,
-}
-
-/// Error loading the configuration.
-#[derive(Debug, thiserror::Error)]
-pub enum ConfigError {
-    /// Error loading from environment variable
-    #[error("missing or non-unicode environment variable: {0}")]
-    Var(String),
-    /// Error parsing environment variable
-    #[error("failed to parse environment variable: {0}")]
-    Parse(#[from] num::ParseIntError),
-    /// Error parsing boolean environment variable
-    #[error("failed to parse boolean environment variable")]
-    ParseBool,
-    /// Error parsing hex from environment variable
-    #[error("failed to parse hex: {0}")]
-    Hex(#[from] hex::FromHexError),
-    /// Error connecting to the provider
-    #[error("failed to connect to provider: {0}")]
-    Provider(#[from] alloy::transports::TransportError),
-    /// Error connecting to the signer
-    #[error("failed to connect to signer: {0}")]
-    Signer(#[from] SignerError),
-    /// I/O error
-    #[error("I/O error: {0}")]
-    Io(#[from] std::io::Error),
-}
 
-impl ConfigError {
-    /// Missing or non-unicode env var.
-    pub fn missing(s: &str) -> Self {
-        ConfigError::Var(s.to_string())
-    }
+    /// The slot calculator for the builder.
+    pub slot_calculator: SlotCalculator,
 }
 
-/// Type alias for the provider used to build and submit blocks to the host.
-pub type HostProvider = FillProvider<
-    JoinFill<
-        JoinFill<
-            Identity,
-            JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
-        >,
-        WalletFiller<EthereumWallet>,
-    >,
-    RootProvider,
-    Ethereum,
->;
-
 /// Type alias for the provider used to simulate against rollup state.
 pub type RuProvider = RootProvider<Ethereum>;
 
@@ -159,90 +162,48 @@ pub type RuProvider = RootProvider<Ethereum>;
 pub type ZenithInstance<P = HostProvider> = Zenith::ZenithInstance<(), P, alloy::network::Ethereum>;
 
 impl BuilderConfig {
-    /// Load the builder configuration from environment variables.
-    pub fn load_from_env() -> Result<BuilderConfig, ConfigError> {
-        Ok(BuilderConfig {
-            host_chain_id: load_u64(HOST_CHAIN_ID)?,
-            ru_chain_id: load_u64(RU_CHAIN_ID)?,
-            host_rpc_url: load_url(HOST_RPC_URL)?,
-            ru_rpc_url: load_url(ROLLUP_RPC_URL)?,
-            tx_broadcast_urls: env::var(TX_BROADCAST_URLS)
-                .unwrap_or_default()
-                .split(',')
-                .map(str::trim)
-                .filter(|url| !url.is_empty())
-                .map(ToOwned::to_owned)
-                .map(Into::into)
-                .collect(),
-            zenith_address: load_address(ZENITH_ADDRESS)?,
-            builder_helper_address: load_address(BUILDER_HELPER_ADDRESS)?,
-            quincey_url: load_url(QUINCEY_URL)?,
-            builder_port: load_u16(BUILDER_PORT)?,
-            sequencer_key: load_string_option(SEQUENCER_KEY),
-            builder_key: load_string(BUILDER_KEY)?,
-            block_confirmation_buffer: load_u64(BLOCK_CONFIRMATION_BUFFER)?,
-            chain_offset: load_u64(CHAIN_OFFSET)?,
-            target_slot_time: load_u64(TARGET_SLOT_TIME)?,
-            builder_rewards_address: load_address(BUILDER_REWARDS_ADDRESS)?,
-            rollup_block_gas_limit: load_u64(ROLLUP_BLOCK_GAS_LIMIT)?,
-            tx_pool_url: load_url(TX_POOL_URL)?,
-            tx_pool_cache_duration: load_u64(TX_POOL_CACHE_DURATION)?,
-            oauth_client_id: load_string(OAUTH_CLIENT_ID)?,
-            oauth_client_secret: load_string(OAUTH_CLIENT_SECRET)?,
-            oauth_authenticate_url: load_string(OAUTH_AUTHENTICATE_URL)?,
-            oauth_token_url: load_string(OAUTH_TOKEN_URL)?,
-            oauth_token_refresh_interval: load_u64(AUTH_TOKEN_REFRESH_INTERVAL)?,
-            concurrency_limit: load_concurrency_limit()?,
-            start_timestamp: load_u64(START_TIMESTAMP)?,
-        })
-    }
-
     /// Connect to the Builder signer.
-    pub async fn connect_builder_signer(&self) -> Result<LocalOrAws, ConfigError> {
-        LocalOrAws::load(&self.builder_key, Some(self.host_chain_id)).await.map_err(Into::into)
+    pub async fn connect_builder_signer(&self) -> Result<LocalOrAws, SignerError> {
+        LocalOrAws::load(&self.builder_key, Some(self.host_chain_id)).await
     }
 
     /// Connect to the Sequencer signer.
-    pub async fn connect_sequencer_signer(&self) -> Result<Option<LocalOrAws>, ConfigError> {
-        match &self.sequencer_key {
-            Some(sequencer_key) => LocalOrAws::load(sequencer_key, Some(self.host_chain_id))
+    pub async fn connect_sequencer_signer(&self) -> eyre::Result<Option<LocalOrAws>> {
+        if let Some(sequencer_key) = &self.sequencer_key {
+            LocalOrAws::load(sequencer_key, Some(self.host_chain_id))
                 .await
                 .map_err(Into::into)
-                .map(Some),
-            None => Ok(None),
+                .map(Some)
+        } else {
+            Ok(None)
         }
     }
 
     /// Connect to the Rollup rpc provider.
-    pub async fn connect_ru_provider(&self) -> Result<RootProvider<Ethereum>, ConfigError> {
+    pub fn connect_ru_provider(&self) -> RootProvider<Ethereum> {
         let url = url::Url::parse(&self.ru_rpc_url).expect("failed to parse URL");
-        let provider = RootProvider::<Ethereum>::new_http(url);
-        Ok(provider)
+        RootProvider::<Ethereum>::new_http(url)
     }
 
     /// Connect to the Host rpc provider.
-    pub async fn connect_host_provider(&self) -> Result<HostProvider, ConfigError> {
+    pub async fn connect_host_provider(&self) -> eyre::Result<HostProvider> {
         let builder_signer = self.connect_builder_signer().await?;
-        let provider = ProviderBuilder::new()
+        ProviderBuilder::new()
             .wallet(EthereumWallet::from(builder_signer))
             .connect(&self.host_rpc_url)
             .await
-            .map_err(ConfigError::Provider)?;
-
-        Ok(provider)
+            .map_err(Into::into)
     }
 
     /// Connect additional broadcast providers.
-    pub async fn connect_additional_broadcast(&self) -> Result<Vec<RootProvider>, ConfigError> {
-        let mut providers: Vec<RootProvider> = Vec::with_capacity(self.tx_broadcast_urls.len());
-
-        for url_str in self.tx_broadcast_urls.iter() {
-            let url = url::Url::parse(url_str).expect("failed to parse URL");
-            let provider = RootProvider::new_http(url);
-            providers.push(provider);
-        }
-
-        Ok(providers)
+    pub fn connect_additional_broadcast(&self) -> Vec<RootProvider> {
+        self.tx_broadcast_urls
+            .iter()
+            .map(|url_str| {
+                let url = url::Url::parse(url_str).expect("failed to parse URL");
+                RootProvider::new_http(url)
+            })
+            .collect::<Vec<_>>()
     }
 
     /// Connect to the Zenith instance, using the specified provider.
@@ -276,50 +237,3 @@ impl BuilderConfig {
         SignetSystemConstants::new(host, rollup)
     }
 }
-
-/// Load a string from an environment variable.
-pub fn load_string(key: &str) -> Result<String, ConfigError> {
-    env::var(key).map_err(|_| ConfigError::missing(key))
-}
-
-/// Load a string from an environment variable, returning None if the variable
-/// is not set.
-fn load_string_option(key: &str) -> Option<String> {
-    load_string(key).ok()
-}
-
-/// Load a boolean from an environment variable.
-pub fn load_u64(key: &str) -> Result<u64, ConfigError> {
-    let val = load_string(key)?;
-    val.parse::<u64>().map_err(Into::into)
-}
-
-/// Load a u16 from an environment variable.
-fn load_u16(key: &str) -> Result<u16, ConfigError> {
-    let val = load_string(key)?;
-    val.parse::<u16>().map_err(Into::into)
-}
-
-/// Load a URL from an environment variable.
-pub fn load_url(key: &str) -> Result<Cow<'static, str>, ConfigError> {
-    load_string(key).map(Into::into)
-}
-
-/// Load an address from an environment variable.
-pub fn load_address(key: &str) -> Result<Address, ConfigError> {
-    let address = load_string(key)?;
-    Address::from_str(&address)
-        .map_err(|_| ConfigError::Var(format!("Invalid address format for {}", key)))
-}
-
-/// Checks the configured concurrency parameter and, if none is set, checks the available
-/// system concurrency with `std::thread::available_parallelism` and returns that.
-pub fn load_concurrency_limit() -> Result<usize, ConfigError> {
-    match load_u16(CONCURRENCY_LIMIT) {
-        Ok(env) => Ok(env as usize),
-        Err(_) => {
-            let limit = std::thread::available_parallelism()?.get();
-            Ok(limit)
-        }
-    }
-}
diff --git a/src/tasks/submit.rs b/src/tasks/submit.rs
index 3d3c2db..ff5db52 100644
--- a/src/tasks/submit.rs
+++ b/src/tasks/submit.rs
@@ -206,7 +206,7 @@ impl SubmitTask {
         let fut = spawn_provider_send!(&self.host_provider, &tx);
 
         // Spawn send_tx futures for all additional broadcast host_providers
-        for host_provider in self.config.connect_additional_broadcast().await? {
+        for host_provider in self.config.connect_additional_broadcast() {
             spawn_provider_send!(&host_provider, &tx);
         }
 
diff --git a/src/test_utils.rs b/src/test_utils.rs
index 2e6fc8d..1102835 100644
--- a/src/test_utils.rs
+++ b/src/test_utils.rs
@@ -11,6 +11,7 @@ use alloy::{
 };
 use chrono::{DateTime, Utc};
 use eyre::Result;
+use init4_bin_base::utils::calc::SlotCalculator;
 use std::{
     str::FromStr,
     time::{Instant, SystemTime},
@@ -31,8 +32,7 @@ pub fn setup_test_config() -> Result<BuilderConfig> {
         sequencer_key: None,
         builder_key: "0000000000000000000000000000000000000000000000000000000000000000".into(),
         block_confirmation_buffer: 1,
-        chain_offset: 0,
-        target_slot_time: 1,
+
         builder_rewards_address: Address::default(),
         rollup_block_gas_limit: 3_000_000_000,
         tx_pool_url: "http://localhost:9000/".into(),
@@ -44,7 +44,10 @@ pub fn setup_test_config() -> Result<BuilderConfig> {
         oauth_token_refresh_interval: 300, // 5 minutes
         builder_helper_address: Address::default(),
         concurrency_limit: 1000,
-        start_timestamp: 1740681556, // pecorino start timestamp as sane default
+        slot_calculator: SlotCalculator::new(
+            1740681556, // pecorino start timestamp as sane default
+            0, 1,
+        ),
     };
     Ok(config)
 }
diff --git a/tests/block_builder_test.rs b/tests/block_builder_test.rs
index 8d2e65a..739189e 100644
--- a/tests/block_builder_test.rs
+++ b/tests/block_builder_test.rs
@@ -108,13 +108,7 @@ mod tests {
         // Create a rollup provider
         let ru_provider = RootProvider::<Ethereum>::new_http(anvil_instance.endpoint_url());
 
-        // Create a builder with a test slot calculator
-        let slot_calculator = SlotCalculator::new(
-            config.start_timestamp,
-            config.chain_offset,
-            config.target_slot_time,
-        );
-        let sim = Arc::new(Simulator::new(&config, ru_provider.clone(), slot_calculator));
+        let sim = Arc::new(Simulator::new(&config, ru_provider.clone(), config.slot_calculator));
 
         // Create a shared sim cache
         let sim_cache = SimCache::new();