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:
2026-10-02 20:08:14 -05:00
co-authored by Claude Opus 5.5
parent a3361020d1
commit 5246898968
26 changed files with 468 additions and 162 deletions
+17 -12
View File
@@ -1031,9 +1031,7 @@ void I18n::loadBuiltinEnglish()
strings_["copied"] = "Copied!";
strings_["hidden_tag"] = " (hidden)";
strings_["z_address"] = "Z-Address";
strings_["t_address"] = "T-Address";
strings_["shielded_address"] = "Shielded Address";
strings_["transparent_address"] = "Transparent Address";
strings_["label_placeholder"] = "e.g. Savings, Mining...";
strings_["choose_icon"] = "Choose Icon";
strings_["clear_icon"] = "Clear Icon";
@@ -1169,7 +1167,6 @@ void I18n::loadBuiltinEnglish()
// Balance Tab
strings_["summary"] = "Summary";
strings_["shielded"] = "Shielded";
strings_["transparent"] = "Transparent";
strings_["total"] = "Total";
strings_["unconfirmed"] = "Unconfirmed";
strings_["recent_transactions"] = "RECENT TRANSACTIONS";
@@ -1180,7 +1177,6 @@ void I18n::loadBuiltinEnglish()
strings_["privacy_low"] = "Low privacy — shield funds";
strings_["balance_history_collecting"] = "Balance history — collecting data...";
strings_["balance_shielded_fmt"] = "Shielded: %.8f";
strings_["balance_transparent_fmt"] = "Transparent: %.8f";
strings_["total_balance_label"] = "Total Balance";
strings_["balance_syncing_pct"] = "Syncing %.1f%%";
strings_["balance_mining_rate"] = "Mining %s";
@@ -1194,7 +1190,6 @@ void I18n::loadBuiltinEnglish()
strings_["t_addresses"] = "T-Addresses";
strings_["no_addresses"] = "No addresses found. Create one using the buttons above.";
strings_["new_z_address"] = "New Z-Address";
strings_["new_t_address"] = "New T-Address";
strings_["type"] = "Type";
strings_["address"] = "Address";
strings_["copy_address"] = "Copy Full Address";
@@ -1792,7 +1787,6 @@ void I18n::loadBuiltinEnglish()
strings_["contact_avatar_image"] = "Image";
strings_["contact_avatar_badge_hint"] = "The badge is chosen automatically from the address type.";
strings_["contact_avatar_shielded"] = "Shielded";
strings_["contact_avatar_transparent"] = "Transparent";
strings_["contact_avatar_choose"] = "Choose image\xE2\x80\xA6";
strings_["contact_avatar_remove"] = "Remove";
strings_["contact_avatar_image_hint"] = "The image is copied into the app so it stays available if the original moves.";
@@ -2170,6 +2164,23 @@ void I18n::loadBuiltinEnglish()
strings_["mining_payout_address"] = "Payout Address";
strings_["mining_payout_tooltip"] = "Address to receive mining rewards";
strings_["mining_payout_invalid"] = "Not a valid DragonX address — fix it before starting, or mining rewards are lost.";
strings_["send_mining_addr_short"] = "Mining address — can't be paid";
strings_["send_mining_addr_blocked"] = "This is a mining (transparent) address. On DragonX these can only receive mining rewards — the network rejects payments to them. Ask the recipient for a shielded address (it starts with zs).";
strings_["mining_payout_needs_shielded"] = "Pools pay out with ordinary transactions, which can't reach a mining (transparent, R…) address on DragonX. Use a shielded address (it starts with zs) as your payout address.";
strings_["new_mining_address"] = "New mining address";
strings_["tt_new_mining_address"] = "Creates a transparent (R…) address for solo-mining rewards. It can't receive payments — share a shielded address for those.";
strings_["mining_address"] = "Mining address";
strings_["addr_type_mining"] = "Mining";
strings_["mining_rewards"] = "Mining rewards";
strings_["mining_rewards_unshielded"] = "Not yet shielded";
strings_["baltab_mining_addresses_count"] = "%d mining addresses";
strings_["baltab_mining_amount"] = "Mining rewards %.8f";
strings_["balance_mining_fmt"] = "Mining rewards: %.8f";
strings_["mining_card_tooltip"] = "Solo-mining rewards arrive at your mining (transparent, R…) addresses. Those addresses can't receive payments. Rewards are shielded automatically once they mature.";
strings_["mining_card_click_to_shield"] = "Click to shield matured rewards now.";
strings_["contact_chip_mining"] = "Mining only";
strings_["failed_create_mining_address"] = "Failed to create mining address";
strings_["new_mining_address_created"] = "New mining address created";
strings_["mining_est_daily_pool_sub"] = "rough solo-equivalent, before pool fee";
strings_["mining_generate_z_address_hint"] = "Generate a Z address in the Receive tab to use as your payout address";
strings_["mining_pool_needs_payout_tooltip"] = "Enter a payout address first (generate a Z address)";
@@ -2388,9 +2399,7 @@ void I18n::loadBuiltinEnglish()
strings_["click_copy_uri"] = "Click to copy URI";
strings_["generating"] = "Generating";
strings_["failed_create_shielded"] = "Failed to create shielded address";
strings_["failed_create_transparent"] = "Failed to create transparent address";
strings_["new_shielded_created"] = "New shielded address created";
strings_["new_transparent_created"] = "New transparent address created";
strings_["payment_request_copied"] = "Payment request copied";
strings_["payment_uri_copied"] = "Payment URI copied";
@@ -2453,7 +2462,6 @@ void I18n::loadBuiltinEnglish()
strings_["send_txid_copied"] = "TxID copied to clipboard";
strings_["send_txid_label"] = "TxID: %s";
strings_["send_valid_shielded"] = "Valid shielded address";
strings_["send_valid_transparent"] = "Valid transparent address";
strings_["send_wallet_empty"] = "Your wallet is empty";
strings_["send_yes_clear"] = "Yes, Clear";
@@ -2708,15 +2716,12 @@ void I18n::loadBuiltinEnglish()
// balance_tab.cpp
strings_["baltab_shielded_amount"] = "Shielded %.8f";
strings_["baltab_transparent_amount"] = "Transparent %.8f";
strings_["baltab_market_price_4dp"] = "Market: $%.4f";
strings_["baltab_market_price_8dp"] = "Market: $%.8f";
strings_["baltab_pct_of_total_zaddr"] = "%.0f%% of total · %d Z-addr";
strings_["baltab_t_addresses_count"] = "%d T-addresses";
strings_["baltab_pct_change_24h"] = "%s%.1f%% 24h";
strings_["baltab_total_balance"] = "Total Balance";
strings_["baltab_shielded"] = "Shielded";
strings_["baltab_transparent"] = "Transparent";
strings_["baltab_market"] = "Market";
// settings_window.cpp