feat(wallet): consolidate notes per address, keeping each address's funds in place

Users who keep funds apart under different labelled addresses can now
shed notes (smaller wallet, faster scans/witness rebuilds) without the
funds being merged into a single address.

- Merge/Consolidate dialog: "Where should the funds go?" - Into one
  address (unchanged) or Keep in each address. The latter lists shielded
  addresses with 2+ spendable notes (label, note count, amount;
  too-small ones disabled) and merges each address's notes back into
  that address with z_mergetoaddress [addr] addr. Addresses with more
  notes than the batch size get several batches (the daemon locks a
  batch's notes before returning, so calls take disjoint notes); the
  dialog suggests a second run after those confirm. Per-address
  progress; ops keep running if the dialog is closed. The Consolidate
  (wallet-size) preset opens in this mode; Merge keeps "Into one".
  Shielded only: a transparent address can't take a merge's output.
- services/note_consolidation: groupSpendableNotes, worthConsolidating,
  estimateBatches, consolidateInPlace (pure; driven by a merge-call
  function), with unit tests against a stand-in following dragonxd's
  rules.
- fake_dragonxd: optional note wallet (FAKE_WALLET_NOTES,
  FAKE_MERGE_SECS) with z_mergetoaddress and its operations.
- i18n: 17 new keys in all 8 languages; CJK subset rebuilt.
- UI sweep: modal-consolidate target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 22:15:56 -05:00
co-authored by Claude Opus 5.5
parent e367eb47ff
commit 71ed92b9f1
19 changed files with 1016 additions and 6 deletions
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "Fundir múltiplos UTXOs em um único endereço blindado. Isso pode ajudar a reduzir o tamanho da carteira e melhorar a privacidade.",
"merge_fee_hint": "Taxa de rede para esta transação.",
"merge_funds": "Fundir Fundos",
"merge_into_one": "Para um só endereço",
"merge_keep_each": "Manter em cada endereço",
"merge_keep_each_batches_fmt": "Endereços com mais de %d notas são mesclados em vários lotes; execute de novo depois que forem confirmados para mesclar o restante.",
"merge_keep_each_confirm_fmt": "Consolidar %d notas em %d endereços? Cada endereço mantém seus próprios fundos. Taxas: cerca de %s DRGX (uma por lote).",
"merge_keep_each_desc": "As notas de cada endereço são mescladas de volta nesse mesmo endereço, então os fundos que você mantém separados com rótulos diferentes continuam separados. Só endereços blindados — fundos transparentes só podem ser blindados (Para um só endereço).",
"merge_keep_each_none": "Cada endereço blindado já tem uma única nota — nada a consolidar.",
"merge_keep_each_nothing_submitted": "Nada foi consolidado — o nó recusou todas as mesclagens.",
"merge_keep_each_row_fmt": "%s · %d notas · %s DRGX",
"merge_keep_each_run_again": "Endereços mesclados em vários lotes agora têm uma nota por lote. Execute de novo depois que forem confirmados para mesclá-las em uma.",
"merge_keep_each_select": "Marque pelo menos um endereço para consolidar.",
"merge_keep_each_some_failed": "Algumas mesclagens falharam — veja a lista acima.",
"merge_keep_each_status_done": "%s — concluído: %d notas mescladas em %d lote(s)",
"merge_keep_each_status_failed": "%s — falhou: %s",
"merge_keep_each_status_not_started": "%s — não iniciado: %s",
"merge_keep_each_status_running": "%s — mesclando %d notas (%d de %d lotes concluídos)…",
"merge_keep_each_too_small": "Pequeno demais para consolidar: a taxa consumiria esses fundos.",
"merge_max_inputs": "Máx. de entradas por lote",
"merge_no_spendable": "Ainda não há entradas disponíveis para consolidar.",
"merge_progress": "Consolidando… isso pode levar alguns minutos. Você pode fechar esta janela.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "Transparente",
"merge_started": "Operação de fusão iniciada",
"merge_title": "Fundir para Endereço",
"merge_where": "Para onde devem ir os fundos?",
"mig_adopt": "Tornar esta minha carteira",
"mig_adopt_now": "Adotar carteira semente",
"mig_adopting": "Instalando sua nova carteira e reescaneando…",