// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #include "wallet_state.h" #include "../util/text_format.h" // util::formatClockDateTime (app-wide 24h/12h clock) #include #include #include #include namespace dragonx { std::vector sortedSpendableAddressIndices(const std::vector& addresses, bool requirePositiveBalance) { std::vector indices; indices.reserve(addresses.size()); for (size_t i = 0; i < addresses.size(); ++i) { const auto& address = addresses[i]; if (!address.isSpendable()) continue; // Rank/filter by the CONFIRMED balance — an address holding only 0-conf change can't be sent from. if (requirePositiveBalance && address.spendableBalance <= 0.0) continue; indices.push_back(i); } std::sort(indices.begin(), indices.end(), [&](size_t lhs, size_t rhs) { return addresses[lhs].spendableBalance > addresses[rhs].spendableBalance; }); return indices; } int bestSpendableAddressIndex(const std::vector& addresses) { int bestIndex = -1; double bestBalance = 0.0; for (size_t i = 0; i < addresses.size(); ++i) { if (addresses[i].isSpendable() && addresses[i].spendableBalance > bestBalance) { bestBalance = addresses[i].spendableBalance; bestIndex = static_cast(i); } } return bestIndex; } int addressIndexByString(const std::vector& addresses, const std::string& address) { if (address.empty()) return -1; for (size_t i = 0; i < addresses.size(); ++i) { if (addresses[i].address == address) return static_cast(i); } return -1; } SourceSelection resolveSourceSelection(const std::vector& addresses, const std::string& current, bool autoLatched, bool connected) { SourceSelection r; r.address = current; r.autoLatched = autoLatched; r.index = addressIndexByString(addresses, current); if (!autoLatched && connected && !addresses.empty()) { if (current.empty()) { // only ever fill an empty source const int best = bestSpendableAddressIndex(addresses); if (best >= 0) { r.address = addresses[best].address; r.index = best; } } r.autoLatched = true; // one shot, whether or not it picked } return r; } std::string TransactionInfo::getTimeString() const { if (timestamp == 0) return "Unknown"; return util::formatClockDateTime(timestamp); } std::string TransactionInfo::getTypeDisplay() const { if (type == "send") return "Sent"; if (type == "receive") return "Received"; if (type == "mined" || type == "generate" || type == "immature") return "Mined"; return type; } std::string PeerInfo::getConnectionTime() const { if (conntime == 0) return "Unknown"; int64_t now = std::time(nullptr); int64_t diff = now - conntime; if (diff < 60) return std::to_string(diff) + "s"; if (diff < 3600) return std::to_string(diff / 60) + "m"; if (diff < 86400) return std::to_string(diff / 3600) + "h"; return std::to_string(diff / 86400) + "d"; } std::string BannedPeer::getBannedUntilString() const { if (banned_until == 0) return "Never"; return util::formatClockDateTime(banned_until); } } // namespace dragonx