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

@@ -35,6 +35,7 @@
#include "rpc/connection.h"
#include "chat/chat_identity.h" // deriveChatIdentityFromSecret for HushChat identity provisioning
#include "ui/windows/chat_tab.h" // ui::ResetChatTab — wipe chat UI plaintext on a wallet switch
#include "ui/windows/mining_pool_panel.h" // ui::resolveMiningUserAddress
#include <sodium.h> // sodium_memzero for wiping the fetched mnemonic
#include <cctype>
#include "config/settings.h"
@@ -2288,27 +2289,23 @@ void App::startPoolMining(int threads)
cfg.tls = settings_->getPoolTls();
cfg.hugepages = settings_->getPoolHugepages();
// Use first shielded address as the mining wallet address, fall back to transparent
// xmrig "user" is the pool login the block rewards are credited to. The user's
// "Payout Address" field (cfg.worker_name = getPoolWorker) is exactly that, so it
// takes priority — otherwise a payout address that differs from the wallet's own
// first z-address is silently ignored and rewards go to the wrong address. Only when
// no payout address is set do we fall back to the wallet's own first shielded, then
// transparent, address (available even before the daemon is connected/synced).
std::string firstShielded, firstTransparent;
for (const auto& addr : state_.z_addresses) {
if (!addr.address.empty()) {
cfg.wallet_address = addr.address;
if (!addr.address.empty()) { firstShielded = addr.address; break; }
}
for (const auto& addr : state_.addresses) {
if (addr.type == "transparent" && !addr.address.empty()) {
firstTransparent = addr.address;
break;
}
}
if (cfg.wallet_address.empty()) {
for (const auto& addr : state_.addresses) {
if (addr.type == "transparent" && !addr.address.empty()) {
cfg.wallet_address = addr.address;
break;
}
}
}
// Fallback: use pool worker address from settings (available even before
// the daemon is connected or the blockchain is synced).
if (cfg.wallet_address.empty() && !cfg.worker_name.empty()) {
cfg.wallet_address = cfg.worker_name;
}
cfg.wallet_address = ui::resolveMiningUserAddress(cfg.worker_name, firstShielded, firstTransparent);
if (cfg.wallet_address.empty()) {
DEBUG_LOGF("[ERROR] Pool mining: No wallet address available\n");