From cfbe0545601032eee86f2e23b4dd017999ad37bb Mon Sep 17 00:00:00 2001
From: hinto-janaiyo <hinto.janaiyo@protonmail.com>
Date: Fri, 30 Dec 2022 19:22:43 -0500
Subject: [PATCH] Status Submenu: Add [Status/P2Pool] UI and data

---
 README.md        |  2 +-
 src/constants.rs | 19 ++++++++++++
 src/disk.rs      | 18 ++++++++++-
 src/helper.rs    | 39 ++++++++++++++++--------
 src/human.rs     |  7 +++++
 src/main.rs      | 21 ++++++++-----
 src/status.rs    | 77 ++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 161 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index c202117..16235fd 100644
--- a/README.md
+++ b/README.md
@@ -482,7 +482,7 @@ You need [`cargo`](https://www.rust-lang.org/learn/get-started), Rust's build to
 
 The `--release` profile in Gupax is set to prefer code performance & small binary sizes over compilation speed (see [`Cargo.toml`](https://github.com/hinto-janaiyo/gupax/blob/main/Cargo.toml)). Gupax itself (with all dependencies already built) takes around 1m30s to build (vs 10s on a normal `--release`) with a Ryzen 5950x.
 
-There are `37` unit tests throughout the codebase files, you should probably run:
+There are `38` unit tests throughout the codebase files, you should probably run:
 ```
 cargo test
 ```
diff --git a/src/constants.rs b/src/constants.rs
index 9ac72fa..e3cb85e 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -176,11 +176,30 @@ pub const STATUS_SUBMENU_PROCESSES: &str = "View the status of process related d
 pub const STATUS_SUBMENU_P2POOL:    &str = "View P2Pool specific data";
 pub const STATUS_SUBMENU_MONERO:    &str = "View general Monero blockchain data";
 pub const STATUS_SUBMENU_PAYOUT:    &str = "The total amount of payouts received via P2Pool across all time";
+//-- P2Pool
 pub const STATUS_SUBMENU_XMR:       &str = "The total of XMR mined via P2Pool across all time";
 pub const STATUS_SUBMENU_LATEST:    &str = "Sort the logs latest to oldest";
 pub const STATUS_SUBMENU_OLDEST:    &str = "Sort the logs oldest to latest";
 pub const STATUS_SUBMENU_BIGGEST:   &str = "Sort the logs by the biggest payouts first";
 pub const STATUS_SUBMENU_SMALLEST:  &str = "Sort the logs by the smallest payouts first";
+pub const STATUS_SUBMENU_AUTOMATIC: &str = "Automatically calculate share/block time with your current P2Pool 1 hour average hashrate";
+pub const STATUS_SUBMENU_MANUAL:    &str = "Manually input a hashrate to calculate share/block time with current P2Pool/Monero network stats";
+pub const STATUS_SUBMENU_HASH:      &str = "Use [Hash] as the hashrate metric";
+pub const STATUS_SUBMENU_KILO:      &str = "Use [Kilo] as the hashrate metric (1,000x hash)";
+pub const STATUS_SUBMENU_MEGA:      &str = "Use [Mega] as the hashrate metric (1,000,000x hash)";
+pub const STATUS_SUBMENU_GIGA:      &str = "Use [Giga] as the hashrate metric (1,000,000,000x hash)";
+pub const STATUS_SUBMENU_P2POOL_BLOCK_MEAN:     &str = "The average time it takes for P2Pool to find a block";
+pub const STATUS_SUBMENU_YOUR_P2POOL_HASHRATE:  &str = "Your 1 hour average hashrate on P2Pool";
+pub const STATUS_SUBMENU_P2POOL_SHARE_MEAN:     &str = "The average time it takes for your hashrate to find a share on P2Pool";
+pub const STATUS_SUBMENU_SOLO_BLOCK_MEAN:       &str = "The average time it would take for your hashrate to find a block solo mining Monero";
+pub const STATUS_SUBMENU_MONERO_DIFFICULTY:     &str = "The current Monero network's difficulty (how many hashes it will take on average to find a block)";
+pub const STATUS_SUBMENU_MONERO_HASHRATE:       &str = "The current Monero network's hashrate";
+pub const STATUS_SUBMENU_P2POOL_DIFFICULTY:     &str = "The current P2Pool network's difficulty (how many hashes it will take on average to find a share)";
+pub const STATUS_SUBMENU_P2POOL_HASHRATE:       &str = "The current P2Pool network's hashrate";
+pub const STATUS_SUBMENU_P2POOL_MINERS:         &str = "The current amount of miners on P2Pool";
+pub const STATUS_SUBMENU_P2POOL_DOMINANCE:      &str = "The percent of hashrate P2Pool accounts for in the entire Monero network";
+pub const STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE: &str = "The percent of hashrate you account for in P2Pool";
+pub const STATUS_SUBMENU_YOUR_MONERO_DOMINANCE: &str = "The percent of hashrate you account for in the entire Monero network";
 
 // Gupax
 pub const GUPAX_UPDATE:           &str = "Check for updates on Gupax, P2Pool, and XMRig via GitHub's API and upgrade automatically";
diff --git a/src/disk.rs b/src/disk.rs
index 4a6eadd..4613b1f 100644
--- a/src/disk.rs
+++ b/src/disk.rs
@@ -239,6 +239,12 @@ impl State {
 		}
 	}
 
+	pub fn update_absolute_path(&mut self) -> Result<(), TomlError> {
+		self.gupax.absolute_p2pool_path = into_absolute_path(self.gupax.p2pool_path.clone())?;
+		self.gupax.absolute_xmrig_path = into_absolute_path(self.gupax.xmrig_path.clone())?;
+		Ok(())
+	}
+
 	// Convert [&str] to [State]
 	pub fn from_str(string: &str) -> Result<Self, TomlError> {
 		match toml::de::from_str(string) {
@@ -869,6 +875,15 @@ impl Default for Hash {
 }
 
 impl Hash {
+	pub fn convert_to_hash(f: f64, from: Self) -> f64 {
+		match from {
+			Self::Hash => f,
+			Self::Kilo => f * 1_000.0,
+			Self::Mega => f * 1_000_000.0,
+			Self::Giga => f * 1_000_000_000.0,
+		}
+	}
+
 	pub fn convert(f: f64, og: Self, new: Self) -> f64 {
 		match og {
 			Self::Hash => {
@@ -1034,7 +1049,7 @@ impl Default for Status {
 			payout_view: PayoutView::default(),
 			monero_enabled: false,
 			manual_hash: false,
-			hashrate: 0.0,
+			hashrate: 1.0,
 			hash_metric: Hash::default(),
 		}
 	}
@@ -1064,6 +1079,7 @@ impl Default for Gupax {
 		}
 	}
 }
+
 impl Default for P2pool {
 	fn default() -> Self {
 		Self {
diff --git a/src/helper.rs b/src/helper.rs
index 6d3249b..c5c79d6 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -1239,17 +1239,18 @@ pub struct PubP2poolApi {
 	pub average_effort: HumanNumber,
 	pub current_effort: HumanNumber,
 	pub connections: HumanNumber,
-	// The API below needs a raw int [hashrate] to go off of and
+	// The API needs a raw ints to go off of and
 	// there's not a good way to access it without doing weird
-	// [Arc<Mutex>] shenanigans, so the raw [hashrate_1h] is
-	// copied here instead.
-	pub hashrate: u64,
+	// [Arc<Mutex>] shenanigans, so some raw ints are stored here.
+	pub user_p2pool_hashrate_u64: u64,
+	pub p2pool_difficulty_u64: u64,
+	pub monero_difficulty_u64: u64,
 	// Network API
 	pub monero_difficulty: HumanNumber, // e.g: [15,000,000]
 	pub monero_hashrate: HumanNumber,   // e.g: [1.000 GH/s]
-	pub hash: String,
+	pub hash: String, // Current block hash
 	pub height: HumanNumber,
-	pub reward: u64, // Atomic units
+	pub reward: AtomicUnit,
 	// Pool API
 	pub p2pool_difficulty: HumanNumber,
 	pub p2pool_hashrate: HumanNumber,
@@ -1290,12 +1291,14 @@ impl PubP2poolApi {
 			average_effort: HumanNumber::unknown(),
 			current_effort: HumanNumber::unknown(),
 			connections: HumanNumber::unknown(),
-			hashrate: 0,
+			user_p2pool_hashrate_u64: 0,
+			p2pool_difficulty_u64: 0,
+			monero_difficulty_u64: 0,
 			monero_difficulty: HumanNumber::unknown(),
 			monero_hashrate: HumanNumber::unknown(),
 			hash: String::from("???"),
 			height: HumanNumber::unknown(),
-			reward: 0,
+			reward: AtomicUnit::new(),
 			p2pool_difficulty: HumanNumber::unknown(),
 			p2pool_hashrate: HumanNumber::unknown(),
 			miners: HumanNumber::unknown(),
@@ -1407,14 +1410,14 @@ impl PubP2poolApi {
 			average_effort: HumanNumber::to_percent(local.average_effort),
 			current_effort: HumanNumber::to_percent(local.current_effort),
 			connections: HumanNumber::from_u16(local.connections),
-			hashrate: local.hashrate_1h,
+			user_p2pool_hashrate_u64: local.hashrate_1h,
 			..std::mem::take(&mut *public)
 		};
 	}
 
 	// Mutate [PubP2poolApi] with data from a [PrivP2pool(Network|Pool)Api].
 	fn update_from_network_pool(public: &Arc<Mutex<Self>>, net: PrivP2poolNetworkApi, pool: PrivP2poolPoolApi) {
-		let user_hashrate = lock!(public).hashrate; // The user's total P2Pool hashrate
+		let user_hashrate = lock!(public).user_p2pool_hashrate_u64; // The user's total P2Pool hashrate
 		let monero_difficulty = net.difficulty;
 		let monero_hashrate = monero_difficulty / MONERO_BLOCK_TIME_IN_SECONDS;
 		let p2pool_hashrate = pool.pool_statistics.hashRate;
@@ -1452,11 +1455,13 @@ impl PubP2poolApi {
 		}
 		let mut public = lock!(public);
 		*public = Self {
+			p2pool_difficulty_u64: p2pool_difficulty,
+			monero_difficulty_u64: monero_difficulty,
 			monero_difficulty: HumanNumber::from_u64(monero_difficulty),
 			monero_hashrate: HumanNumber::from_u64_to_gigahash_3_point(monero_hashrate),
 			hash: net.hash,
 			height: HumanNumber::from_u32(net.height),
-			reward: net.reward,
+			reward: AtomicUnit::from_u64(net.reward),
 			p2pool_difficulty: HumanNumber::from_u64(p2pool_difficulty),
 			p2pool_hashrate: HumanNumber::from_u64_to_megahash_3_point(p2pool_hashrate),
 			miners: HumanNumber::from_u32(pool.pool_statistics.miners),
@@ -1469,6 +1474,14 @@ impl PubP2poolApi {
 			..std::mem::take(&mut *public)
 		};
 	}
+
+	pub fn calculate_share_or_block_time(hashrate: u64, difficulty: u64) -> HumanTime {
+		if hashrate == 0 {
+			HumanTime::new()
+		} else {
+			HumanTime::from_u64(difficulty / hashrate)
+		}
+	}
 }
 
 //---------------------------------------------------------------------------------------------------- Private P2Pool "Local" Api
@@ -1889,7 +1902,7 @@ mod test {
 		assert_eq!(p.average_effort.to_string(), "100.00%");
 		assert_eq!(p.current_effort.to_string(), "200.00%");
 		assert_eq!(p.connections.to_string(),    "1,234");
-		assert_eq!(p.hashrate,                   20000);
+		assert_eq!(p.user_p2pool_hashrate_u64,   20000);
 		drop(p);
 		// Update Network + Pool
 		PubP2poolApi::update_from_network_pool(&public, network, pool);
@@ -1899,7 +1912,7 @@ mod test {
 		assert_eq!(p.monero_hashrate.to_string(),     "2.500 GH/s");
 		assert_eq!(p.hash.to_string(),                "asdf");
 		assert_eq!(p.height.to_string(),              "1,234");
-		assert_eq!(p.reward,                          2345);
+		assert_eq!(p.reward.to_u64(),                 2345);
 		assert_eq!(p.p2pool_difficulty.to_string(),   "10,000,000");
 		assert_eq!(p.p2pool_hashrate.to_string(),     "1.000 MH/s");
 		assert_eq!(p.miners.to_string(),              "1,000");
diff --git a/src/human.rs b/src/human.rs
index e5034ce..e62356d 100644
--- a/src/human.rs
+++ b/src/human.rs
@@ -44,6 +44,10 @@ impl HumanTime {
 		HumanTime(d)
 	}
 
+	pub const fn from_u64(u: u64) -> HumanTime {
+		HumanTime(Duration::from_secs(u))
+	}
+
 	fn plural(f: &mut std::fmt::Formatter, started: &mut bool, name: &str, value: u64) -> std::fmt::Result {
 		if value > 0 {
 			if *started {
@@ -216,6 +220,9 @@ impl HumanNumber {
 		let f = format!("{}", f);
 		Self(f)
 	}
+	pub fn as_str(&self) -> &str {
+		self.0.as_str()
+	}
 }
 
 //---------------------------------------------------------------------------------------------------- TESTS
diff --git a/src/main.rs b/src/main.rs
index 13d3fd5..d31a543 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1520,6 +1520,8 @@ impl eframe::App for App {
 								});
 							} else if p2pool_is_alive {
 								if key.is_up() && !wants_input || ui.add_sized([width, height], Button::new("⟲")).on_hover_text("Restart P2Pool").clicked() {
+									lock!(self.og).update_absolute_path();
+									self.state.update_absolute_path();
 									Helper::restart_p2pool(&self.helper, &self.state.p2pool, &self.state.gupax.absolute_p2pool_path);
 								}
 								if key.is_down() && !wants_input || ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop P2Pool").clicked() {
@@ -1549,6 +1551,8 @@ impl eframe::App for App {
 								ui.set_enabled(ui_enabled);
 								let color = if ui_enabled { GREEN } else { RED };
 								if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new(RichText::new("▶").color(color))).on_hover_text("Start P2Pool").on_disabled_hover_text(text).clicked() {
+									lock!(self.og).update_absolute_path();
+									self.state.update_absolute_path();
 									Helper::start_p2pool(&self.helper, &self.state.p2pool, &self.state.gupax.absolute_p2pool_path);
 								}
 							}
@@ -1575,6 +1579,8 @@ impl eframe::App for App {
 								});
 							} else if xmrig_is_alive {
 								if key.is_up() && !wants_input || ui.add_sized([width, height], Button::new("⟲")).on_hover_text("Restart XMRig").clicked() {
+									lock!(self.og).update_absolute_path();
+									self.state.update_absolute_path();
 									if cfg!(windows) {
 										Helper::restart_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
 									} else {
@@ -1609,14 +1615,15 @@ impl eframe::App for App {
 								}
 								ui.set_enabled(ui_enabled);
 								let color = if ui_enabled { GREEN } else { RED };
-								#[cfg(target_os = "windows")]
 								if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new(RichText::new("▶").color(color))).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
-									Helper::start_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
-								}
-								#[cfg(target_family = "unix")]
-								if (ui_enabled && key.is_up() && !wants_input) || ui.add_sized([width, height], Button::new(RichText::new("▶").color(color))).on_hover_text("Start XMRig").on_disabled_hover_text(text).clicked() {
-									lock!(self.sudo).signal = ProcessSignal::Start;
-									self.error_state.ask_sudo(&self.sudo);
+									lock!(self.og).update_absolute_path();
+									self.state.update_absolute_path();
+									if cfg!(windows) {
+										Helper::start_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path, Arc::clone(&self.sudo));
+									} else if cfg!(unix) {
+										lock!(self.sudo).signal = ProcessSignal::Start;
+										self.error_state.ask_sudo(&self.sudo);
+									}
 								}
 							}
 						});
diff --git a/src/status.rs b/src/status.rs
index e238ab9..150792c 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -27,6 +27,7 @@ use crate::{
 	macros::*,
 	GupaxP2poolApi,
 	PayoutView,
+	human::HumanNumber,
 };
 use std::sync::{Arc,Mutex};
 use log::*;
@@ -36,6 +37,7 @@ use egui::{
 	TextStyle::Name,
 	TextEdit,
 	SelectableLabel,
+	Slider,
 };
 
 impl crate::disk::Status {
@@ -172,6 +174,81 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
 		});
 	});
 	drop(api);
+	// Payout/Share Calculator
+	let button = (width/20.0)-(SPACE*1.666);
+	ui.group(|ui| { ui.horizontal(|ui| {
+		ui.set_min_width(width-SPACE);
+		if ui.add_sized([button*2.0, text], SelectableLabel::new(self.manual_hash == false, "Automatic")).on_hover_text(STATUS_SUBMENU_AUTOMATIC).clicked() {self.manual_hash = false; }
+		ui.separator();
+		if ui.add_sized([button*2.0, text], SelectableLabel::new(self.manual_hash == true, "Manual")).on_hover_text(STATUS_SUBMENU_MANUAL).clicked() { self.manual_hash = true; }
+		ui.separator();
+		ui.set_enabled(self.manual_hash);
+		if ui.add_sized([button, text], SelectableLabel::new(self.hash_metric == Hash::Hash, "Hash")).on_hover_text(STATUS_SUBMENU_HASH).clicked() { self.hash_metric = Hash::Hash; }
+		ui.separator();
+		if ui.add_sized([button, text], SelectableLabel::new(self.hash_metric == Hash::Kilo, "Kilo")).on_hover_text(STATUS_SUBMENU_KILO).clicked() { self.hash_metric = Hash::Kilo; }
+		ui.separator();
+		if ui.add_sized([button, text], SelectableLabel::new(self.hash_metric == Hash::Mega, "Mega")).on_hover_text(STATUS_SUBMENU_MEGA).clicked() { self.hash_metric = Hash::Mega; }
+		ui.separator();
+		if ui.add_sized([button, text], SelectableLabel::new(self.hash_metric == Hash::Giga, "Giga")).on_hover_text(STATUS_SUBMENU_GIGA).clicked() { self.hash_metric = Hash::Giga; }
+		ui.separator();
+		ui.spacing_mut().slider_width = button*12.5;
+		ui.add_sized([button*14.0, text], Slider::new(&mut self.hashrate, 1.0..=1_000.0));
+	})});
+	let api = lock!(p2pool_api);
+	ui.set_enabled(p2pool_alive);
+	let text = height / 25.0;
+	let width = (width/3.0)-(SPACE*1.666);
+	let min_height = ui.available_height()/1.25;
+	ui.horizontal(|ui| {
+	ui.group(|ui| { ui.vertical(|ui| {
+		ui.set_min_height(min_height);
+		if self.manual_hash {
+			let hashrate          = Hash::convert_to_hash(self.hashrate, self.hash_metric) as u64;
+			let p2pool_share_mean = PubP2poolApi::calculate_share_or_block_time(hashrate, api.p2pool_difficulty_u64);
+			let solo_block_mean   = PubP2poolApi::calculate_share_or_block_time(hashrate, api.monero_difficulty_u64);
+			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
+			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
+			ui.add_sized([width, text], Label::new(format!("{} H/s", HumanNumber::from_u64(hashrate))));
+			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Share Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
+			ui.add_sized([width, text], Label::new(p2pool_share_mean.to_string()));
+			ui.add_sized([width, text], Label::new(RichText::new("Your Solo Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(solo_block_mean.to_string()));
+		} else {
+			ui.add_sized([width, text], Label::new(RichText::new("P2Pool Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(api.p2pool_block_mean.to_string()));
+			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_HASHRATE);
+			ui.add_sized([width, text], Label::new(format!("{} H/s", api.hashrate_1h)));
+			ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Share Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_SHARE_MEAN);
+			ui.add_sized([width, text], Label::new(api.p2pool_share_mean.to_string()));
+			ui.add_sized([width, text], Label::new(RichText::new("Your Solo Block Mean").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_SOLO_BLOCK_MEAN);
+			ui.add_sized([width, text], Label::new(api.solo_block_mean.to_string()));
+		}
+	})});
+	ui.group(|ui| { ui.vertical(|ui| {
+		ui.set_min_height(min_height);
+		ui.add_sized([width, text], Label::new(RichText::new("Monero Difficulty").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_MONERO_DIFFICULTY);
+		ui.add_sized([width, text], Label::new(api.monero_difficulty.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("Monero Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_MONERO_HASHRATE);
+		ui.add_sized([width, text], Label::new(api.monero_hashrate.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("P2Pool Difficulty").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_DIFFICULTY);
+		ui.add_sized([width, text], Label::new(api.p2pool_difficulty.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("P2Pool Hashrate").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_HASHRATE);
+		ui.add_sized([width, text], Label::new(api.p2pool_hashrate.as_str()));
+	})});
+	ui.group(|ui| { ui.vertical(|ui| {
+		ui.set_min_height(min_height);
+		ui.add_sized([width, text], Label::new(RichText::new("P2Pool Miners").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_MINERS);
+		ui.add_sized([width, text], Label::new(api.miners.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("P2Pool Dominance").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_P2POOL_DOMINANCE);
+		ui.add_sized([width, text], Label::new(api.p2pool_percent.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("Your P2Pool Dominance").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_P2POOL_DOMINANCE);
+		ui.add_sized([width, text], Label::new(api.user_p2pool_percent.as_str()));
+		ui.add_sized([width, text], Label::new(RichText::new("Your Monero Dominance").underline().color(BONE))).on_hover_text(STATUS_SUBMENU_YOUR_MONERO_DOMINANCE);
+		ui.add_sized([width, text], Label::new(api.user_monero_percent.as_str()));
+	})});
+	});
+	drop(api);
 	//---------------------------------------------------------------------------------------------------- [Monero]
 	} else if self.submenu == Submenu::Monero {
 	}