1use alloy::{
2 primitives::{utils::format_ether, Address},
3 providers::ProviderBuilder,
4};
5use anyhow::{Context as _, Result};
6use espresso_types::{
7 v0_3::{Fetcher, Validator},
8 L1Client,
9};
10use hotshot_contract_adapter::sol_types::StakeTableV2;
11use hotshot_types::signature_key::BLSPubKey;
12use url::Url;
13
14use crate::{output::output_success, parse::Commission};
15
16pub async fn stake_table_info(
17 l1_url: Url,
18 stake_table_address: Address,
19 l1_block_number: u64,
20) -> Result<Vec<Validator<BLSPubKey>>> {
21 let l1 = L1Client::new(vec![l1_url])?;
22 let (validators, _) =
23 Fetcher::fetch_all_validators_from_contract(l1, stake_table_address, l1_block_number)
24 .await?;
25
26 Ok(validators
27 .into_iter()
28 .map(|(_address, validator)| validator)
29 .collect())
30}
31
32pub fn display_stake_table(stake_table: Vec<Validator<BLSPubKey>>, compact: bool) -> Result<()> {
33 let mut stake_table = stake_table.clone();
34 stake_table.sort_by(|a, b| a.stake.cmp(&b.stake));
35
36 for validator in stake_table.iter() {
37 let comm: Commission = validator.commission.try_into()?;
38 let bls_key = validator.stake_table_key.to_string();
39 let key_str = if compact {
40 let end = bls_key.chars().map(|c| c.len_utf8()).take(40).sum();
41 format!("{}..", &bls_key[..end])
42 } else {
43 bls_key.to_string()
44 };
45 output_success(format!(
46 "Validator {}: {key_str} comm={comm} stake={} ESP",
47 validator.account,
48 format_ether(validator.stake),
49 ));
50
51 if validator.delegators.is_empty() {
52 output_success(" - No delegators");
53 continue;
54 }
55
56 let mut delegators = validator.delegators.iter().collect::<Vec<_>>();
58 delegators.sort_by(|a, b| a.0.cmp(b.0));
59 for (delegator, stake) in delegators {
60 output_success(format!(
61 " - Delegator {delegator}: stake={} ESP",
62 format_ether(*stake)
63 ));
64 }
65 }
66 Ok(())
67}
68
69pub async fn fetch_token_address(rpc_url: Url, stake_table_address: Address) -> Result<Address> {
70 let provider = ProviderBuilder::new().connect_http(rpc_url);
71 StakeTableV2::new(stake_table_address, provider)
72 .token()
73 .call()
74 .await
75 .with_context(|| {
76 format!(
77 "Failed to fetch token address from stake table contract at {stake_table_address}"
78 )
79 })
80}