diff --git a/Cargo.toml b/Cargo.toml index c3d14ca..47069dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "ghost-eye" authors = ["str3tch "] description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost" -version = "0.3.36" +version = "0.3.37" edition = "2021" [dependencies] diff --git a/src/action.rs b/src/action.rs index eddb318..830c5e7 100644 --- a/src/action.rs +++ b/src/action.rs @@ -104,6 +104,7 @@ pub enum Action { GetErasStakersOverview([u8; 32], bool), GetValidatorPrefs([u8; 32], bool), GetSlashingSpans([u8; 32], bool), + GetValidatorLatestClaim([u8; 32], bool), GetCurrentValidatorEraRewards, SetNodeName(Option), @@ -133,6 +134,7 @@ pub enum Action { SetValidatorEraClaimed(u32, bool), SetValidatorEraSlash(u32, u128), SetValidatorEraUnlocking(u32, u128, [u8; 32]), + SetValidatorLatestClaim(u32, [u8; 32]), SetIsBonded(bool), SetStakedAmountRatio(u128, u128, [u8; 32]), SetStakedRatio(u128, u128, [u8; 32]), diff --git a/src/components/nominator/current_validator_details.rs b/src/components/nominator/current_validator_details.rs index 3fded61..2d32667 100644 --- a/src/components/nominator/current_validator_details.rs +++ b/src/components/nominator/current_validator_details.rs @@ -23,6 +23,7 @@ pub struct CurrentValidatorDetails { others_len: usize, commission: f64, points_ratio: f64, + latest_era_claim: u32, is_active_validator: bool, is_nomination_disabled: bool, } @@ -49,6 +50,7 @@ impl CurrentValidatorDetails { commission: 0.0, points_ratio: 0.0, palette: Default::default(), + latest_era_claim: 0, is_active_validator: false, is_nomination_disabled: false, } @@ -102,6 +104,7 @@ impl CurrentValidatorDetails { let _ = network_tx.send(Action::GetNominatorsByValidator(account_id, false)); let _ = network_tx.send(Action::GetValidatorPrefs(account_id, false)); let _ = network_tx.send(Action::GetValidatorLedger(account_id, false)); + let _ = network_tx.send(Action::GetValidatorLatestClaim(account_id, false)); } } } @@ -136,10 +139,12 @@ impl Component for CurrentValidatorDetails { Action::SetValidatorPrefs(commission, is_disabled, account_id) if self.choosen == account_id => self.update_commission(commission, is_disabled), Action::SetNominatorsByValidator(noms, account_id) if self.choosen == account_id => self.others_len = noms.len(), Action::SetStakedAmountRatio(_, active_stake, account_id) if self.choosen == account_id => self.active_stake = active_stake, + Action::SetValidatorLatestClaim(era_index, account_id) if self.choosen == account_id => self.latest_era_claim = era_index, Action::SetStakedRatio(total, own, account_id) if self.choosen == account_id => { self.total_balance = total; self.own_balance = own; }, + _ => {} }; Ok(None) @@ -183,6 +188,10 @@ impl Component for CurrentValidatorDetails { Cell::from(Text::from("Imbalance".to_string()).alignment(Alignment::Left)), Cell::from(Text::from(self.prepare_stake_imbalance()).alignment(Alignment::Right)), ]), + Row::new(vec![ + Cell::from(Text::from("Last payout".to_string()).alignment(Alignment::Left)), + Cell::from(Text::from(format!("{} days ago", self.latest_era_claim)).alignment(Alignment::Right)), + ]), ], [ Constraint::Max(12), diff --git a/src/network/mod.rs b/src/network/mod.rs index 88a52a2..3e1d4ad 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -205,6 +205,10 @@ impl Network { Ok(()) } + Action::GetValidatorLatestClaim(account_id, is_stash) => { + self.store_stash_or_validator_if_possible(account_id, is_stash); + predefined_calls::get_validator_latest_claim(&self.action_tx, &self.online_client_api, &account_id).await + } Action::GetSlashingSpans(account_id, is_stash) => { self.store_stash_or_validator_if_possible(account_id, is_stash); predefined_calls::get_slashing_spans(&self.action_tx, &self.online_client_api, &account_id).await diff --git a/src/network/predefined_calls.rs b/src/network/predefined_calls.rs index e683432..e01f177 100644 --- a/src/network/predefined_calls.rs +++ b/src/network/predefined_calls.rs @@ -534,3 +534,32 @@ pub async fn get_slashing_spans( action_tx.send(Action::SetSlashingSpansLength(slashing_spans_length, *account_id))?; Ok(()) } + +pub async fn get_validator_latest_claim( + action_tx: &UnboundedSender, + api: &OnlineClient, + account_id: &[u8; 32], +) -> Result<()> { + let current_era = super::raw_calls::staking::current_era(api, None).await?.unwrap_or(0); + let era_depth = super::raw_calls::staking::history_depth(api).unwrap_or(0); + + let last_era = current_era.saturating_sub(era_depth); + let mut claimed_era = current_era; + + while claimed_era > last_era { + let is_claimed = super::raw_calls::staking::claimed_rewards(api, None, claimed_era, account_id) + .await? + .map(|claimed_rewards| claimed_rewards.len() > 0) + .unwrap_or_default(); + + if is_claimed { + break; + } + + claimed_era -= 1; + } + + action_tx.send(Action::SetValidatorLatestClaim(current_era.saturating_sub(claimed_era), *account_id))?; + + Ok(()) +}