feat(wallet): wire fmcd as core app + dual-ecash receive

Fedimint never appeared in Wallet > Settings > Fedimint because the
fmcd (fedimint-clientd) sidecar was never installed: ensure_default_
federation() needs the fmcd password to reach the daemon, found none,
and silently no-oped, leaving the registry empty.

- prod_orchestrator: add fedimint-clientd to the baseline auto-install
  set so it self-heals onto every node and auto-joins the default
  federation; generate the fmcd-password secret before secret_env
  resolves.
- fedimint_client: ensure_fmcd_password (random hex, 0600) shared with
  the container's secret_env; from_node reads the same secret (legacy
  fmcd/password kept as fallback); reissue_into_any redeems received
  notes into the first joined federation that accepts them.
- wallet.ecash-receive: dual-token — cashu* tokens redeem at the mint,
  anything else is reissued via fmcd; returns the kind + federation_id.
- UI: receive box advertises "Cashu or Fedimint" and reports which kind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-19 09:52:26 -04:00
co-authored by Claude Opus 4.8
parent 298595069d
commit c4855526fe
4 changed files with 119 additions and 14 deletions
@@ -70,6 +70,10 @@ fn is_required_baseline_app(app_id: &str) -> bool {
| "mempool"
| "archy-mempool-db"
| "filebrowser"
// fmcd: bundled on every node so the wallet's Fedimint side works
// out of the box (auto-joins the default federation). Self-heals if
// removed, like the other baseline services.
| "fedimint-clientd"
)
}
@@ -2728,6 +2732,13 @@ impl ProdContainerOrchestrator {
.await
.context("ensuring bitcoin tx-relay credentials")?;
}
if app_id == "fedimint-clientd" {
// The fmcd container's secret_env (fmcd-password) and the wallet
// bridge both read this; generate it before secret_env resolves.
crate::wallet::fedimint_client::ensure_fmcd_password(&self.secrets_dir)
.await
.context("ensuring fmcd password secret")?;
}
Ok(())
}