feat(ui): treat transparent addresses as mining-only addresses
DragonX is a private chain (-ac_private=1): consensus rejects any
non-coinbase output to a transparent address, so a t-address can only
ever receive mining rewards, and its coins can only move to a shielded
address. The wallet treated them like ordinary recipients.
Block paying one:
- Send: a transparent recipient shows "Mining address - can't be paid"
and disables Review Send (tooltip explains; ask for a zs... address).
Typing, paste, contacts and payment URIs all go through this field.
- Overview drag-to-transfer: a mining-address row is never a transfer
target (it only reorders).
- Pool payout must be shielded (pools pay with ordinary transactions):
field tooltip, disabled Start button and the start check say why.
- isValidRecipientAddress() is now shielded-only; new isDragonXAddress()
and classifyRecipient() (Shielded / MiningOnly / Invalid).
Call them mining addresses:
- Overview: "Mining rewards" card (amber "Not yet shielded" when there
is a balance; hover explains; click opens the Shield dialog), "New
mining address" button with a tooltip, rows typed "Mining".
- QR / label dialogs, portfolio filter, contact badge ("Mining only"),
Receive notifications.
i18n: 17 new keys in all 8 languages, 12 dead keys removed, CJK subset
rebuilt. Tests: recipient classification, translation completeness.
UI sweep: new "send-mining-recipient" target.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "qr_popup_dialog.h"
|
||||
#include "address_label_dialog.h"
|
||||
#include "address_transfer_dialog.h"
|
||||
#include "shield_dialog.h"
|
||||
#include "send_tab.h"
|
||||
#include "../../app.h"
|
||||
#include "../../config/settings.h"
|
||||
@@ -531,7 +532,7 @@ static void RenderBalanceClassic(App* app)
|
||||
float cy = cMin.y + cardPadLg;
|
||||
|
||||
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(cx, cy),
|
||||
OnSurfaceMedium(), TR("transparent"));
|
||||
OnSurfaceMedium(), TR("mining_rewards"));
|
||||
cy += ovFont->LegacySize + ovGap;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%.8f", s_dispTransparent);
|
||||
@@ -543,18 +544,24 @@ static void RenderBalanceClassic(App* app)
|
||||
OnSurfaceMedium(), DRAGONX_TICKER);
|
||||
cy += sub1->LegacySize + valGap;
|
||||
|
||||
snprintf(buf, sizeof(buf), TR("baltab_t_addresses_count"),
|
||||
(int)state.t_addresses.size());
|
||||
// Rewards waiting at a mining address: say so, and let a click shield them now.
|
||||
const bool unshielded = s_dispTransparent > 0.0;
|
||||
if (unshielded) snprintf(buf, sizeof(buf), "%s", TR("mining_rewards_unshielded"));
|
||||
else snprintf(buf, sizeof(buf), TR("baltab_mining_addresses_count"), (int)state.t_addresses.size());
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(cx, cy),
|
||||
OnSurfaceDisabled(), buf);
|
||||
unshielded ? amberCol : OnSurfaceDisabled(), buf);
|
||||
|
||||
// Hover glow + click to Receive
|
||||
// Hover glow + explain; click shields waiting rewards (else opens Receive)
|
||||
if (material::IsRectHovered(cMin, cMax)) {
|
||||
dl->AddRect(cMin, cMax, IM_COL32(255, 255, 255, (int)S.drawElement("tabs.balance", "hover-glow-alpha").sizeOr(40.0f)),
|
||||
cardSpec.rounding, 0, S.drawElement("tabs.balance", "hover-glow-thickness").sizeOr(1.5f) * dp);
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (ImGui::IsMouseClicked(0))
|
||||
app->setCurrentPage(NavPage::Receive);
|
||||
material::Tooltip("%s%s%s", TR("mining_card_tooltip"), unshielded ? "\n\n" : "",
|
||||
unshielded ? TR("mining_card_click_to_shield") : "");
|
||||
if (ImGui::IsMouseClicked(0)) {
|
||||
if (unshielded) ShieldDialog::showShieldCoinbase();
|
||||
else app->setCurrentPage(NavPage::Receive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -803,7 +810,7 @@ static void RenderBalanceDonut(App* app) {
|
||||
|
||||
// Transparent legend
|
||||
dl->AddCircleFilled(ImVec2(legendX + 5 * dp, legendY + capFont->LegacySize * 0.5f), legendDotR, Warning());
|
||||
snprintf(buf, sizeof(buf), TR("baltab_transparent_amount"), s_dispTransparent);
|
||||
snprintf(buf, sizeof(buf), TR("baltab_mining_amount"), s_dispTransparent);
|
||||
dl->AddText(capFont, capFont->LegacySize, ImVec2(legendX + legendXOff, legendY), Warning(), buf);
|
||||
legendY += capFont->LegacySize + legendSectionGap;
|
||||
|
||||
@@ -976,7 +983,7 @@ static void RenderBalanceConsolidated(App* app) {
|
||||
// Transparent bar
|
||||
float transX = cardMin.x + pad * 2 + halfW;
|
||||
barY = divY + Layout::spacingSm();
|
||||
std::string transLabelUpper = TR("transparent");
|
||||
std::string transLabelUpper = TR("mining_rewards");
|
||||
std::transform(transLabelUpper.begin(), transLabelUpper.end(), transLabelUpper.begin(),
|
||||
[](unsigned char c){ return (char)std::toupper(c); });
|
||||
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(transX, barY), Warning(), transLabelUpper.c_str());
|
||||
@@ -1100,7 +1107,7 @@ static void RenderBalanceDashboard(App* app) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return (char)std::toupper(c); });
|
||||
return s;
|
||||
};
|
||||
std::string lblShielded = upperTR("shielded"), lblTransparent = upperTR("transparent");
|
||||
std::string lblShielded = upperTR("shielded"), lblTransparent = upperTR("mining_rewards");
|
||||
std::string lblQuickSend = upperTR("quick_send"), lblQuickReceive = upperTR("quick_receive");
|
||||
|
||||
TileInfo tiles[4] = {
|
||||
@@ -1240,7 +1247,7 @@ static void RenderBalanceVerticalStack(App* app) {
|
||||
RowInfo rowInfos[4] = {
|
||||
{TR("baltab_total_balance"), ICON_MD_ACCOUNT_BALANCE_WALLET, S.resolveColor("var(--accent-total)", OnSurface()), s_dispTotal, 1.0f},
|
||||
{TR("baltab_shielded"), ICON_MD_SHIELD, S.resolveColor("var(--accent-shielded)", Success()), s_dispShielded, shieldRatio},
|
||||
{TR("baltab_transparent"), ICON_MD_CIRCLE, S.resolveColor("var(--accent-transparent)", Warning()), s_dispTransparent, transRatio},
|
||||
{TR("mining_rewards"), ICON_MD_CIRCLE, S.resolveColor("var(--accent-transparent)", Warning()), s_dispTransparent, transRatio},
|
||||
{TR("baltab_market"), ICON_MD_TRENDING_UP, S.resolveColor("var(--accent-action)", Primary()), state.market.price_usd, 0.0f},
|
||||
};
|
||||
|
||||
@@ -1437,7 +1444,7 @@ static void RenderBalanceVertical2x2(App* app) {
|
||||
// Row 1: Market (left), Transparent (right)
|
||||
{
|
||||
{TR("baltab_market"), ICON_MD_TRENDING_UP, S.resolveColor("var(--accent-action)", Primary()), state.market.price_usd, 0.0f, true, false},
|
||||
{TR("baltab_transparent"), ICON_MD_CIRCLE, S.resolveColor("var(--accent-transparent)", Warning()), s_dispTransparent, transRatio, false, true},
|
||||
{TR("mining_rewards"), ICON_MD_CIRCLE, S.resolveColor("var(--accent-transparent)", Warning()), s_dispTransparent, transRatio, false, true},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1696,7 +1703,7 @@ static void RenderBalanceShield(App* app) {
|
||||
std::string shieldLabelUpper = TR("shielded");
|
||||
std::transform(shieldLabelUpper.begin(), shieldLabelUpper.end(), shieldLabelUpper.begin(),
|
||||
[](unsigned char c){ return (char)std::toupper(c); });
|
||||
std::string transLabelUpper = TR("transparent");
|
||||
std::string transLabelUpper = TR("mining_rewards");
|
||||
std::transform(transLabelUpper.begin(), transLabelUpper.end(), transLabelUpper.begin(),
|
||||
[](unsigned char c){ return (char)std::toupper(c); });
|
||||
dl->AddText(ovFont, ovFont->LegacySize, ImVec2(infoX, infoY), Success(), shieldLabelUpper.c_str());
|
||||
@@ -1855,7 +1862,7 @@ static void RenderBalanceTimeline(App* app) {
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return (char)std::toupper(c); });
|
||||
return s;
|
||||
};
|
||||
std::string cShielded = upperTR("shielded"), cTransparent = upperTR("transparent"), cMarket = upperTR("market");
|
||||
std::string cShielded = upperTR("shielded"), cTransparent = upperTR("mining_rewards"), cMarket = upperTR("market");
|
||||
SumCard cards[3] = {
|
||||
{cShielded.c_str(), Success(), s_dispShielded, false},
|
||||
{cTransparent.c_str(), Warning(), s_dispTransparent, false},
|
||||
@@ -2137,7 +2144,7 @@ static void RenderBalanceMinimal(App* app) {
|
||||
snprintf(buf, sizeof(buf), TR("balance_shielded_fmt"), s_dispShielded);
|
||||
Type().textColored(TypeStyle::Caption, Success(), buf);
|
||||
ImGui::SameLine(0, Layout::spacingLg());
|
||||
snprintf(buf, sizeof(buf), TR("balance_transparent_fmt"), s_dispTransparent);
|
||||
snprintf(buf, sizeof(buf), TR("balance_mining_fmt"), s_dispTransparent);
|
||||
Type().textColored(TypeStyle::Caption, Warning(), buf);
|
||||
|
||||
// USD value
|
||||
|
||||
Reference in New Issue
Block a user