Skip to content

Commit c505b40

Browse files
committed
feat: rebalancer service
1 parent 8d839a6 commit c505b40

File tree

11 files changed

+547
-43
lines changed

11 files changed

+547
-43
lines changed

Cargo.lock

Lines changed: 27 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"crates/rbuilder-config",
1414
"crates/rbuilder",
1515
"crates/rbuilder-operator",
16+
"crates/rbuilder-rebalancer",
1617
"crates/reth-rbuilder",
1718
"crates/rbuilder/src/test_utils",
1819
"crates/rbuilder/src/telemetry/metrics_macros",

crates/bid-scraper/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ tokio-util.workspace = true
2020
tracing = "0.1.37"
2121
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
2222
log = "^0.4"
23-
clap = { version = "^3.2", features = ["derive"] }
23+
clap.workspace = true
2424
serde_json = { workspace = true }
2525
serde = { workspace = true }
2626
serde_with = { version = "3.9.0", features = ["time_0_3"] }
@@ -41,7 +41,7 @@ ssz_types = "^0.5"
4141
hex = "^0.4"
4242
derivative.workspace = true
4343
toml.workspace = true
44-
eyre = "0.6.12"
44+
eyre.workspace = true
4545
thiserror.workspace = true
4646
parking_lot.workspace = true
4747
strum = { version = "0.25", features = ["derive"] }

crates/eth-sparse-mpt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ repository.workspace = true
1010

1111
[dependencies]
1212
thiserror = "1.0.61"
13-
serde = { version = "1.0.203", features = ["derive"] }
13+
serde = { workspace = true, features = ["derive"] }
1414
serde_json = "1.0.117"
1515
serde_with = "3.9.0"
1616
rustc-hash = "2.0.0"

crates/rbuilder-config/src/logger.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
use tracing_subscriber::EnvFilter;
22

33
/// Logger configuration.
4-
#[derive(Debug, Clone)]
4+
#[derive(PartialEq, Eq, Clone, Debug, serde::Deserialize)]
55
pub struct LoggerConfig {
66
pub env_filter: String,
7+
#[serde(default)]
78
pub log_json: bool,
9+
#[serde(default)]
810
pub log_color: bool,
911
}
1012

13+
impl LoggerConfig {
14+
/// Default logger configuration for development.
15+
pub fn dev() -> Self {
16+
Self {
17+
env_filter: String::from("info"),
18+
log_color: true,
19+
log_json: false,
20+
}
21+
}
22+
}
23+
1124
impl LoggerConfig {
1225
/// Initialize tracing subscriber based on the configuration.
1326
pub fn init_tracing(self) -> eyre::Result<()> {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "rbuilder-rebalancer"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
10+
[dependencies]
11+
rbuilder-config.workspace = true
12+
13+
alloy-primitives = { workspace = true, features = ["serde"] }
14+
alloy-eips.workspace = true
15+
alloy-consensus.workspace = true
16+
alloy-rpc-types-eth.workspace = true
17+
alloy-provider.workspace = true
18+
alloy-signer.workspace = true
19+
alloy-signer-local.workspace = true
20+
21+
# rt
22+
tokio = { workspace = true, default-features = false, features = ["macros", "rt-multi-thread"] }
23+
futures.workspace = true
24+
25+
# misc
26+
serde = { workspace = true, features = ["derive"] }
27+
serde_json.workspace = true
28+
clap.workspace = true
29+
eyre.workspace = true
30+
toml.workspace = true
31+
tracing.workspace = true
32+
reqwest.workspace = true
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use alloy_provider::ProviderBuilder;
2+
use alloy_signer_local::PrivateKeySigner;
3+
use clap::Parser;
4+
use rbuilder_rebalancer::{config::RebalancerConfig, rebalancer::Rebalancer};
5+
use std::{path::PathBuf, str::FromStr, time::Duration};
6+
use tracing::{level_filters::LevelFilter, *};
7+
8+
#[tokio::main]
9+
async fn main() {
10+
if let Err(error) = Cli::parse().run().await {
11+
eprintln!("Error: {error:?}");
12+
std::process::exit(1);
13+
}
14+
}
15+
16+
#[derive(Parser)]
17+
struct Cli {
18+
#[clap(env = "REBALANCER_CONFIG", help = "Config file path")]
19+
config: PathBuf,
20+
}
21+
22+
impl Cli {
23+
async fn run(self) -> eyre::Result<()> {
24+
let config = RebalancerConfig::parse_toml_file(&self.config)?;
25+
26+
config.logger.init_tracing()?;
27+
28+
if config.rules.is_empty() {
29+
warn!("No rebalancing rules have been configured, rebalancer will be idling");
30+
}
31+
32+
for rule in &config.rules {
33+
if rule.destination_min_balance >= rule.destination_target_balance {
34+
eyre::bail!("Invalid configuration for rule `{}`: minimum balance must be lower than the target", rule.description);
35+
}
36+
37+
if !config.accounts.iter().any(|acc| acc.id == rule.source_id) {
38+
eyre::bail!("Invalid configuration for rule `{}`: account entry is missing for source account {}", rule.description, rule.source_id);
39+
}
40+
}
41+
42+
let rpc_provider = ProviderBuilder::new().connect(&config.rpc_url).await?;
43+
let transfer_max_priority_fee_per_gas =
44+
config.transfer_max_priority_fee_per_gas.try_into().unwrap();
45+
let accounts = config
46+
.accounts
47+
.into_iter()
48+
.map(|account| {
49+
let account = account.map_secret(|secret| {
50+
let secret = secret.value().expect("invalid env");
51+
PrivateKeySigner::from_str(&secret).expect("invalid private key")
52+
});
53+
(account.id.clone(), account)
54+
})
55+
.collect();
56+
Rebalancer::new(
57+
rpc_provider,
58+
config.builder_url,
59+
transfer_max_priority_fee_per_gas,
60+
accounts,
61+
config.rules,
62+
Duration::from_secs(2),
63+
Duration::from_secs(2),
64+
)
65+
.run()
66+
.await
67+
}
68+
}

0 commit comments

Comments
 (0)