feat(mining): live pool fee, saved/custom pool rows, and payout-address fix

Several related mining-tab pool improvements:

- Report the default pool fee correctly: pool.dragonx.is is 1%, not 0%.
  The registry constant was hardcoded to 0. It now also fetches the live
  poolFee from the pool's /api/stats alongside hashrate (no extra
  request), so the displayed fee self-corrects and falls back to the
  compile-time value only when the fetch hasn't landed.

- Show fractional fees: new FormatFeePercent trims trailing zeros so
  whole fees read "1%" and fractional ones keep their decimals ("1.5%").

- Surface saved + custom pools in the pool list card: the list is now
  the union of the official pools, the user's saved favorites, and the
  currently-mined pool (effectivePools), each a selectable, endpoint-
  deduped row. Previously the card only showed the hardcoded knownPools().

- Fix the xmrig "user" field: the "Payout Address" field now drives the
  pool login rewards are credited to (resolveMiningUserAddress), instead
  of being written only to "pass" while "user" was auto-derived from the
  wallet's own first z-address -- which silently ignored a configured
  payout address and could route rewards to the wrong address.

Unit tests cover parsePoolFee, FormatFeePercent, effectivePools, and
resolveMiningUserAddress; full app + ObsidianDragonTests build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 03:48:05 -05:00
parent fffee9f0b5
commit 45b652f514
10 changed files with 311 additions and 27 deletions

View File

@@ -251,11 +251,15 @@ static void RenderLeftPoolCard(App* app, const WalletState& state, ImDrawList* d
}
y += gap * 0.5f;
// The pool list = official pools user-saved favorites the current custom pool.
const auto effective = util::effectivePools(app->settings()->getPoolUrl(),
app->settings()->getSavedPoolUrls());
// --- POOLS (N) header + Refresh ---
{
char hdr[48];
snprintf(hdr, sizeof(hdr), "%s (%d)", TR("mining_pools_header"),
(int)util::knownPools().size());
(int)effective.size());
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(x, y), OnSurfaceMedium(), hdr);
float btnS = ovFont->LegacySize + 6 * dp;
@@ -278,11 +282,11 @@ static void RenderLeftPoolCard(App* app, const WalletState& state, ImDrawList* d
{
ImDrawList* cdl = ImGui::GetWindowDrawList();
const auto snap = app->poolStatsSnapshot();
const util::KnownPool* current = util::findKnownPoolByUrl(app->settings()->getPoolUrl());
const util::KnownPool* current = util::findPoolByUrl(effective, app->settings()->getPoolUrl());
const float childW = ImGui::GetContentRegionAvail().x;
const float listRowH = capFont->LegacySize + 10 * dp;
for (const auto& kp : util::knownPools()) {
for (const auto& kp : effective) {
ImGui::PushID(kp.id.c_str());
const bool isCurrent = current && current->id == kp.id;
const auto it = snap.byId.find(kp.id);
@@ -315,7 +319,17 @@ static void RenderLeftPoolCard(App* app, const WalletState& state, ImDrawList* d
char right[64];
std::string hrStr = haveHr ? FormatHashrate(it->second.hashrateHs) : std::string("");
snprintf(right, sizeof(right), "%s %.0f%% fee", hrStr.c_str(), kp.feePercent);
// Prefer the live fee the pool reports; fall back to the compile-time
// KnownPool.feePercent. A synthetic user pool has an unknown (<0) fee, so
// we show just its hashrate placeholder for it.
double feePct = (it != snap.byId.end() && it->second.feePercent >= 0.0)
? it->second.feePercent
: kp.feePercent;
if (feePct >= 0.0)
snprintf(right, sizeof(right), "%s %s%% fee", hrStr.c_str(),
FormatFeePercent(feePct).c_str());
else
snprintf(right, sizeof(right), "%s", hrStr.c_str());
ImVec2 rSz = capFont->CalcTextSizeA(capFont->LegacySize, FLT_MAX, 0, right);
cdl->AddText(capFont, capFont->LegacySize,
ImVec2(rMax.x - rSz.x - 6 * dp, textY), OnSurfaceMedium(), right);