feat(wallet,content,seed): Fedimint dual-ecash, paid content streaming, seed ceremony

- Fedimint ecash alongside Cashu: fedimint-clientd (fmcd) HTTP bridge,
  fedimint_client, fedimint RPC, wallet wiring
- Paid peer content: content invoices + streaming content server + content RPCs
- Seed-phrase ceremony/reveal RPCs and CLI ceremony tool
- LND wallet, mesh status/messaging, app-stack (netbird HTTPS), and
  decoupled-update wiring; Fedimint Client core app in catalog

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-17 19:21:07 -04:00
co-authored by Claude Opus 4.8
parent c10f2ac22e
commit bd567cd165
34 changed files with 2677 additions and 68 deletions
@@ -110,6 +110,15 @@ impl RpcHandler {
if let Some(name) = params.get("advert_name").and_then(|v| v.as_str()) {
config.advert_name = Some(name.to_string());
}
if let Some(announce) = params
.get("announce_block_headers")
.and_then(|v| v.as_bool())
{
config.announce_block_headers = announce;
}
if let Some(receive) = params.get("receive_block_headers").and_then(|v| v.as_bool()) {
config.receive_block_headers = receive;
}
mesh::save_config(&self.config.data_dir, &config).await?;
@@ -124,6 +133,8 @@ impl RpcHandler {
"configured": true,
"enabled": config.enabled,
"device_path": config.device_path,
"announce_block_headers": config.announce_block_headers,
"receive_block_headers": config.receive_block_headers,
}))
}
}
+13 -6
View File
@@ -5,26 +5,33 @@ use anyhow::Result;
impl RpcHandler {
/// mesh.status — Get mesh radio status, device info, and peer count.
pub(in crate::api::rpc) async fn handle_mesh_status(&self) -> Result<serde_json::Value> {
// Block-header send/receive prefs live in MeshConfig; surface them in
// status so the UI toggles (issue #28) can show the persisted state.
let config = mesh::load_config(&self.config.data_dir).await?;
let service = self.mesh_service.read().await;
if let Some(svc) = service.as_ref() {
let mut value = if let Some(svc) = service.as_ref() {
let status = svc.status().await;
Ok(serde_json::to_value(status)?)
serde_json::to_value(status)?
} else {
// No service running — return basic config + device detection
let config = mesh::load_config(&self.config.data_dir).await?;
let devices = mesh::detect_devices().await;
Ok(serde_json::json!({
serde_json::json!({
"enabled": config.enabled,
"device_connected": false,
"device_type": "unknown",
"device_path": config.device_path,
"channel_name": config.channel_name.unwrap_or_else(|| "archipelago".to_string()),
"channel_name": config.channel_name.clone().unwrap_or_else(|| "archipelago".to_string()),
"detected_devices": devices,
"peer_count": 0,
"messages_sent": 0,
"messages_received": 0,
}))
})
};
if let Some(obj) = value.as_object_mut() {
obj.insert("announce_block_headers".into(), config.announce_block_headers.into());
obj.insert("receive_block_headers".into(), config.receive_block_headers.into());
}
Ok(value)
}
/// mesh.peers — List discovered mesh peers.