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
Binary file not shown.
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "Mehrere UTXOs zu einer einzelnen abgeschirmten Adresse zusammenführen. Dies kann die Wallet-Größe reduzieren und die Privatsphäre verbessern.",
"merge_fee_hint": "Netzwerkgebühr für diese Transaktion.",
"merge_funds": "Gelder zusammenführen",
"merge_into_one": "In eine Adresse",
"merge_keep_each": "In jeder Adresse belassen",
"merge_keep_each_batches_fmt": "Adressen mit mehr als %d Notes werden in mehreren Durchgängen zusammengeführt; führen Sie es nach deren Bestätigung erneut aus, um den Rest zusammenzuführen.",
"merge_keep_each_confirm_fmt": "%d Notes in %d Adressen konsolidieren? Jede Adresse behält ihre eigenen Mittel. Gebühren: etwa %s DRGX (eine pro Durchgang).",
"merge_keep_each_desc": "Die Notes jeder Adresse werden in genau diese Adresse zurückgeführt, sodass Mittel, die Sie unter verschiedenen Bezeichnungen getrennt halten, getrennt bleiben. Nur abgeschirmte Adressen – transparente Mittel können nur abgeschirmt werden (In eine Adresse).",
"merge_keep_each_none": "Jede abgeschirmte Adresse hat bereits nur eine Note – nichts zu konsolidieren.",
"merge_keep_each_nothing_submitted": "Nichts wurde konsolidiert – der Node hat jede Zusammenführung abgelehnt.",
"merge_keep_each_row_fmt": "%s · %d Notes · %s DRGX",
"merge_keep_each_run_again": "Adressen, die in mehreren Durchgängen zusammengeführt wurden, haben jetzt eine Note pro Durchgang. Führen Sie dies nach deren Bestätigung erneut aus, um sie zu einer zusammenzuführen.",
"merge_keep_each_select": "Wählen Sie mindestens eine Adresse zum Konsolidieren aus.",
"merge_keep_each_some_failed": "Einige Zusammenführungen sind fehlgeschlagen – siehe Liste oben.",
"merge_keep_each_status_done": "%s – fertig: %d Notes in %d Durchgang/Durchgängen zusammengeführt",
"merge_keep_each_status_failed": "%s – fehlgeschlagen: %s",
"merge_keep_each_status_not_started": "%s – nicht gestartet: %s",
"merge_keep_each_status_running": "%s – %d Notes werden zusammengeführt (%d von %d Durchgängen fertig)…",
"merge_keep_each_too_small": "Zu klein zum Konsolidieren: Die Gebühr würde diese Mittel aufbrauchen.",
"merge_max_inputs": "Max. Inputs pro Batch",
"merge_no_spendable": "Noch keine verfügbaren Inputs zum Konsolidieren.",
"merge_progress": "Konsolidierung läuft… dies kann einige Minuten dauern. Sie können dieses Fenster schließen.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "Transparent",
"merge_started": "Zusammenführung gestartet",
"merge_title": "An Adresse zusammenführen",
"merge_where": "Wohin sollen die Mittel gehen?",
"mig_adopt": "Dies zu meiner Wallet machen",
"mig_adopt_now": "Seed-Wallet übernehmen",
"mig_adopting": "Ihre neue Wallet wird installiert und neu gescannt…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "Fusiona múltiples UTXOs en una sola dirección protegida. Esto puede ayudar a reducir el tamaño de la cartera y mejorar la privacidad.",
"merge_fee_hint": "Comisión de red para esta transacción.",
"merge_funds": "Fusionar Fondos",
"merge_into_one": "A una sola dirección",
"merge_keep_each": "Mantener en cada dirección",
"merge_keep_each_batches_fmt": "Las direcciones con más de %d notas se fusionan en varios lotes; vuelve a ejecutarlo cuando se confirmen para fusionar el resto.",
"merge_keep_each_confirm_fmt": "¿Consolidar %d notas en %d direcciones? Cada dirección conserva sus propios fondos. Comisiones: unos %s DRGX (una por lote).",
"merge_keep_each_desc": "Las notas de cada dirección se fusionan de nuevo en esa misma dirección, así que los fondos que mantienes separados con distintas etiquetas siguen separados. Solo direcciones blindadas: los fondos transparentes solo pueden blindarse (A una sola dirección).",
"merge_keep_each_none": "Cada dirección blindada ya tiene una sola nota: no hay nada que consolidar.",
"merge_keep_each_nothing_submitted": "No se consolidó nada: el nodo rechazó todas las fusiones.",
"merge_keep_each_row_fmt": "%s · %d notas · %s DRGX",
"merge_keep_each_run_again": "Las direcciones fusionadas en varios lotes tienen ahora una nota por lote. Vuelve a ejecutarlo cuando se confirmen para fusionarlas en una.",
"merge_keep_each_select": "Marca al menos una dirección para consolidar.",
"merge_keep_each_some_failed": "Algunas fusiones fallaron; consulta la lista de arriba.",
"merge_keep_each_status_done": "%s: listo: %d notas fusionadas en %d lote(s)",
"merge_keep_each_status_failed": "%s: falló: %s",
"merge_keep_each_status_not_started": "%s: no iniciado: %s",
"merge_keep_each_status_running": "%s: fusionando %d notas (%d de %d lotes listos)…",
"merge_keep_each_too_small": "Demasiado poco para consolidar: la comisión se llevaría estos fondos.",
"merge_max_inputs": "Máximo de entradas por lote",
"merge_no_spendable": "Aún no hay entradas disponibles para consolidar.",
"merge_progress": "Consolidando… esto puede tardar varios minutos. Puedes cerrar esta ventana.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "Transparentes",
"merge_started": "Operación de fusión iniciada",
"merge_title": "Fusionar a Dirección",
"merge_where": "¿Adónde deben ir los fondos?",
"mig_adopt": "Hacer que esta sea mi cartera",
"mig_adopt_now": "Adoptar cartera con frase",
"mig_adopting": "Instalando tu nueva cartera y reescaneando…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "Fusionnez plusieurs UTXOs en une seule adresse blindée. Cela peut réduire la taille du portefeuille et améliorer la confidentialité.",
"merge_fee_hint": "Frais réseau pour cette transaction.",
"merge_funds": "Fusionner les fonds",
"merge_into_one": "Vers une seule adresse",
"merge_keep_each": "Garder dans chaque adresse",
"merge_keep_each_batches_fmt": "Les adresses de plus de %d notes sont fusionnées en plusieurs lots ; relancez l'opération une fois ceux-ci confirmés pour fusionner le reste.",
"merge_keep_each_confirm_fmt": "Consolider %d notes dans %d adresses ? Chaque adresse garde ses propres fonds. Frais : environ %s DRGX (un par lot).",
"merge_keep_each_desc": "Les notes de chaque adresse sont refusionnées dans cette même adresse : les fonds que vous gardez séparés sous des libellés différents restent séparés. Adresses blindées uniquement — les fonds transparents ne peuvent qu'être blindés (Vers une seule adresse).",
"merge_keep_each_none": "Chaque adresse blindée ne contient déjà qu'une seule note — rien à consolider.",
"merge_keep_each_nothing_submitted": "Rien n'a été consolidé — le nœud a refusé chaque fusion.",
"merge_keep_each_row_fmt": "%s · %d notes · %s DRGX",
"merge_keep_each_run_again": "Les adresses fusionnées en plusieurs lots contiennent maintenant une note par lot. Relancez l'opération une fois ceux-ci confirmés pour les fusionner en une seule.",
"merge_keep_each_select": "Cochez au moins une adresse à consolider.",
"merge_keep_each_some_failed": "Certaines fusions ont échoué — voir la liste ci-dessus.",
"merge_keep_each_status_done": "%s — terminé : %d notes fusionnées en %d lot(s)",
"merge_keep_each_status_failed": "%s — échec : %s",
"merge_keep_each_status_not_started": "%s — non démarré : %s",
"merge_keep_each_status_running": "%s — fusion de %d notes (%d lots sur %d terminés)…",
"merge_keep_each_too_small": "Trop faible pour être consolidé : les frais absorberaient ces fonds.",
"merge_max_inputs": "Nombre max d'entrées par lot",
"merge_no_spendable": "Aucune entrée dépensable à consolider pour l'instant.",
"merge_progress": "Consolidation en cours… cela peut prendre quelques minutes. Vous pouvez fermer cette fenêtre.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "Transparentes",
"merge_started": "Opération de fusion démarrée",
"merge_title": "Fusionner vers une adresse",
"merge_where": "Où doivent aller les fonds ?",
"mig_adopt": "Faire de ceci mon portefeuille",
"mig_adopt_now": "Adopter le portefeuille à phrase",
"mig_adopting": "Installation de votre nouveau portefeuille et rescan en cours…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "複数のUTXOを単一のシールドアドレスに統合します。ウォレットサイズの縮小とプライバシーの向上に役立ちます。",
"merge_fee_hint": "この取引にかかるネットワーク手数料です。",
"merge_funds": "資金を統合",
"merge_into_one": "1 つのアドレスへ",
"merge_keep_each": "各アドレスに残す",
"merge_keep_each_batches_fmt": "ノートが %d 件を超えるアドレスは複数回に分けて統合されます。承認後にもう一度実行すると残りが統合されます。",
"merge_keep_each_confirm_fmt": "%d 件のノートを %d 個のアドレスで統合しますか?各アドレスの資金はそのまま残ります。手数料:約 %s DRGX(1 回ごとに 1 件)。",
"merge_keep_each_desc": "各アドレスのノートはそのアドレス自身に統合されるため、ラベルごとに分けている資金は分かれたままです。シールドアドレスのみ対象です。透明アドレスの資金はシールドすることしかできません(1 つのアドレスへ)。",
"merge_keep_each_none": "すべてのシールドアドレスのノートはすでに 1 つです。統合するものはありません。",
"merge_keep_each_nothing_submitted": "何も統合されませんでした。ノードがすべての統合を拒否しました。",
"merge_keep_each_row_fmt": "%s · ノート %d 件 · %s DRGX",
"merge_keep_each_run_again": "複数回に分けて統合したアドレスには、回数分のノートが残っています。承認後にもう一度実行すると 1 つにまとめられます。",
"merge_keep_each_select": "統合するアドレスを 1 つ以上選んでください。",
"merge_keep_each_some_failed": "一部の統合に失敗しました。上の一覧を確認してください。",
"merge_keep_each_status_done": "%s — 完了:%d 件のノートを %d 回で統合",
"merge_keep_each_status_failed": "%s — 失敗:%s",
"merge_keep_each_status_not_started": "%s — 開始されませんでした:%s",
"merge_keep_each_status_running": "%s — %d 件のノートを統合中(%d / %d 回完了)…",
"merge_keep_each_too_small": "少なすぎて統合できません。手数料でこの資金がなくなります。",
"merge_max_inputs": "バッチあたりの最大入力数",
"merge_no_spendable": "統合できる使用可能な入力がまだありません。",
"merge_progress": "統合中… 数分かかることがあります。このウィンドウは閉じても構いません。",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "透明",
"merge_started": "統合操作を開始しました",
"merge_title": "アドレスに統合",
"merge_where": "資金の移動先",
"mig_adopt": "これを自分のウォレットにする",
"mig_adopt_now": "シードウォレットを採用",
"mig_adopting": "新しいウォレットをインストールして再スキャン中…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "여러 UTXO를 단일 차폐 주소로 통합합니다. 지갑 크기를 줄이고 프라이버시를 향상시킵니다.",
"merge_fee_hint": "이 거래에 대한 네트워크 수수료입니다.",
"merge_funds": "자금 통합",
"merge_into_one": "한 주소로",
"merge_keep_each": "각 주소에 유지",
"merge_keep_each_batches_fmt": "노트가 %d개를 넘는 주소는 여러 번에 나눠 병합됩니다. 확인된 후 다시 실행하면 나머지가 병합됩니다.",
"merge_keep_each_confirm_fmt": "노트 %d개를 주소 %d개에서 통합할까요? 각 주소는 자기 자금을 그대로 유지합니다. 수수료: 약 %s DRGX(배치마다 1회).",
"merge_keep_each_desc": "각 주소의 노트는 같은 주소로 다시 병합되므로, 다른 라벨로 나눠 둔 자금은 계속 나뉜 상태로 유지됩니다. 차폐 주소만 해당되며, 투명 자금은 차폐만 할 수 있습니다(한 주소로).",
"merge_keep_each_none": "모든 차폐 주소에 노트가 이미 하나뿐입니다. 통합할 것이 없습니다.",
"merge_keep_each_nothing_submitted": "아무것도 통합되지 않았습니다. 노드가 모든 병합을 거부했습니다.",
"merge_keep_each_row_fmt": "%s · 노트 %d개 · %s DRGX",
"merge_keep_each_run_again": "여러 번에 나눠 병합된 주소에는 배치마다 노트가 하나씩 남아 있습니다. 확인된 후 다시 실행하면 하나로 병합됩니다.",
"merge_keep_each_select": "통합할 주소를 하나 이상 선택하세요.",
"merge_keep_each_some_failed": "일부 병합에 실패했습니다. 위 목록을 확인하세요.",
"merge_keep_each_status_done": "%s — 완료: 노트 %d개를 %d번에 걸쳐 병합",
"merge_keep_each_status_failed": "%s — 실패: %s",
"merge_keep_each_status_not_started": "%s — 시작되지 않음: %s",
"merge_keep_each_status_running": "%s — 노트 %d개 병합 중(%d/%d 배치 완료)…",
"merge_keep_each_too_small": "너무 적어서 통합할 수 없습니다. 수수료가 이 자금을 모두 소모합니다.",
"merge_max_inputs": "배치당 최대 입력 수",
"merge_no_spendable": "아직 통합할 사용 가능한 입력이 없습니다.",
"merge_progress": "통합 중… 몇 분 정도 걸릴 수 있습니다. 이 창을 닫아도 됩니다.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "투명",
"merge_started": "통합 작업이 시작되었습니다",
"merge_title": "주소로 통합",
"merge_where": "자금을 어디로 보낼까요?",
"mig_adopt": "이 지갑을 내 지갑으로 사용",
"mig_adopt_now": "시드 지갑 사용",
"mig_adopting": "새 지갑을 설치하고 재스캔하는 중…",
+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…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "Объедините несколько UTXO в один экранированный адрес. Это может уменьшить размер кошелька и улучшить конфиденциальность.",
"merge_fee_hint": "Сетевая комиссия за эту транзакцию.",
"merge_funds": "Объединить средства",
"merge_into_one": "На один адрес",
"merge_keep_each": "Оставить в каждом адресе",
"merge_keep_each_batches_fmt": "Адреса с более чем %d заметками объединяются в несколько партий; запустите снова после их подтверждения, чтобы объединить остальное.",
"merge_keep_each_confirm_fmt": "Объединить %d заметок на %d адресах? Каждый адрес сохраняет свои средства. Комиссии: около %s DRGX (по одной на партию).",
"merge_keep_each_desc": "Заметки каждого адреса объединяются обратно в тот же адрес, поэтому средства, которые вы держите раздельно под разными метками, остаются раздельными. Только экранированные адреса — прозрачные средства можно только экранировать («На один адрес»).",
"merge_keep_each_none": "На каждом экранированном адресе уже одна заметка — объединять нечего.",
"merge_keep_each_nothing_submitted": "Ничего не объединено — узел отклонил все объединения.",
"merge_keep_each_row_fmt": "%s · заметок: %d · %s DRGX",
"merge_keep_each_run_again": "На адресах, объединённых в несколько партий, теперь по одной заметке на партию. Запустите снова после их подтверждения, чтобы объединить их в одну.",
"merge_keep_each_select": "Отметьте хотя бы один адрес для объединения.",
"merge_keep_each_some_failed": "Некоторые объединения не удались — см. список выше.",
"merge_keep_each_status_done": "%s — готово: объединено заметок: %d, партий: %d",
"merge_keep_each_status_failed": "%s — ошибка: %s",
"merge_keep_each_status_not_started": "%s — не запущено: %s",
"merge_keep_each_status_running": "%s — объединение %d заметок (готово партий: %d из %d)…",
"merge_keep_each_too_small": "Слишком мало для объединения: комиссия съест эти средства.",
"merge_max_inputs": "Макс. входов за партию",
"merge_no_spendable": "Пока нет доступных для расходования входов для объединения.",
"merge_progress": "Объединение… это может занять несколько минут. Вы можете закрыть это окно.",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "Прозрачные",
"merge_started": "Операция объединения начата",
"merge_title": "Объединить на адрес",
"merge_where": "Куда направить средства?",
"mig_adopt": "Сделать это моим кошельком",
"mig_adopt_now": "Принять сид-кошелёк",
"mig_adopting": "Установка вашего нового кошелька и пересканирование…",
+17
View File
@@ -1163,6 +1163,22 @@
"merge_description": "将多个 UTXO 合并到一个屏蔽地址。这可以帮助减小钱包大小并提高隐私性。",
"merge_fee_hint": "此交易的网络手续费。",
"merge_funds": "合并资金",
"merge_into_one": "合并到一个地址",
"merge_keep_each": "保留在各自地址",
"merge_keep_each_batches_fmt": "超过 %d 张票据的地址会分多批合并;确认后再运行一次即可合并其余部分。",
"merge_keep_each_confirm_fmt": "整合 %d 张票据,涉及 %d 个地址?每个地址保留各自的资金。手续费:约 %s DRGX(每批一次)。",
"merge_keep_each_desc": "每个地址的票据会合并回该地址本身,因此您用不同标签分开存放的资金仍保持分开。仅限屏蔽地址——透明资金只能被屏蔽(合并到一个地址)。",
"merge_keep_each_none": "每个屏蔽地址都只有一张票据——无需整合。",
"merge_keep_each_nothing_submitted": "没有任何整合——节点拒绝了所有合并。",
"merge_keep_each_row_fmt": "%s · %d 张票据 · %s DRGX",
"merge_keep_each_run_again": "分多批合并的地址现在每批各有一张票据。确认后再运行一次,即可把它们合并为一张。",
"merge_keep_each_select": "请至少勾选一个要整合的地址。",
"merge_keep_each_some_failed": "部分合并失败——请查看上方列表。",
"merge_keep_each_status_done": "%s——完成:已合并 %d 张票据,共 %d 批",
"merge_keep_each_status_failed": "%s——失败:%s",
"merge_keep_each_status_not_started": "%s——未开始:%s",
"merge_keep_each_status_running": "%s——正在合并 %d 张票据(已完成 %d/%d 批)…",
"merge_keep_each_too_small": "金额太小,无法整合:手续费会耗尽这些资金。",
"merge_max_inputs": "每批最大输入数",
"merge_no_spendable": "暂无可合并的可用输入。",
"merge_progress": "正在合并…这可能需要几分钟。您可以关闭此窗口。",
@@ -1175,6 +1191,7 @@
"merge_src_transparent": "透明",
"merge_started": "合并操作已开始",
"merge_title": "合并到地址",
"merge_where": "资金应转到哪里?",
"mig_adopt": "将其设为我的钱包",
"mig_adopt_now": "采用助记词钱包",
"mig_adopting": "正在安装您的新钱包并重新扫描…",