diff --git a/core/archipelago/src/api/rpc/lnd/channels.rs b/core/archipelago/src/api/rpc/lnd/channels.rs
index d1603850..c5e58ee4 100644
--- a/core/archipelago/src/api/rpc/lnd/channels.rs
+++ b/core/archipelago/src/api/rpc/lnd/channels.rs
@@ -203,6 +203,29 @@ impl RpcHandler {
.and_then(|v| v.as_bool())
.unwrap_or(false);
+ // Fee control: either a confirmation target or an explicit fee rate
+ let target_conf = params.get("target_conf").and_then(|v| v.as_i64());
+ let sat_per_vbyte = params.get("sat_per_vbyte").and_then(|v| v.as_i64());
+ if target_conf.is_some() && sat_per_vbyte.is_some() {
+ return Err(anyhow::anyhow!(
+ "Invalid fee parameters: specify either target_conf or sat_per_vbyte, not both"
+ ));
+ }
+ if let Some(tc) = target_conf {
+ if !(1..=1008).contains(&tc) {
+ return Err(anyhow::anyhow!(
+ "Invalid target_conf: must be between 1 and 1008 blocks"
+ ));
+ }
+ }
+ if let Some(rate) = sat_per_vbyte {
+ if !(1..=5000).contains(&rate) {
+ return Err(anyhow::anyhow!(
+ "Invalid sat_per_vbyte: must be between 1 and 5000"
+ ));
+ }
+ }
+
info!(
peer = pubkey,
amount = amount,
@@ -250,11 +273,18 @@ impl RpcHandler {
}
}
- let open_body = serde_json::json!({
+ let mut open_body = serde_json::json!({
"node_pubkey_string": pubkey,
"local_funding_amount": amount.to_string(),
"private": private,
});
+ if let Some(tc) = target_conf {
+ open_body["target_conf"] = serde_json::json!(tc);
+ }
+ if let Some(rate) = sat_per_vbyte {
+ // LND REST encodes uint64 as a JSON string
+ open_body["sat_per_vbyte"] = serde_json::json!(rate.to_string());
+ }
let resp = client
.post(format!("{LND_REST_BASE_URL}/v1/channels"))
diff --git a/neode-ui/src/components/LightningChannelsPanel.vue b/neode-ui/src/components/LightningChannelsPanel.vue
new file mode 100644
index 00000000..8834f61b
--- /dev/null
+++ b/neode-ui/src/components/LightningChannelsPanel.vue
@@ -0,0 +1,429 @@
+
+ Total Outbound {{ formatSats(summary.total_outbound) }} Total Inbound {{ formatSats(summary.total_inbound) }} Channels {{ channels.length }} Loading channels... {{ error }} No channels yet Open a channel to start sending and receiving Lightning payments.
+ {{ ch.remote_pubkey }}
+
+ Capacity: {{ formatSats(ch.capacity) }}
+ Format: pubkey@host:port Minimum 20,000 sats
+ {{ feePresets.find(p => p.key === openForm.feePreset)?.hint }}
+ Set one — sats per vByte takes precedence when both are set Some nodes (e.g. LSPs like Olympus) only accept unannounced channels {{ openError }} This will cooperatively close the channel with peer {{ closeTarget.remote_pubkey.slice(0, 16) }}... {{ closeError }}Open Channel
+
+ Close Channel?
+
+ Lightning channels on this node. Open a channel to a peer to send and receive Lightning payments. +
+@@ -145,6 +156,7 @@ import { ref, watch } from 'vue' import { useI18n } from 'vue-i18n' import { rpcClient } from '@/api/rpc-client' import BaseModal from '@/components/BaseModal.vue' +import LightningChannelsPanel from '@/components/LightningChannelsPanel.vue' const { t } = useI18n() @@ -152,10 +164,11 @@ const props = defineProps<{ show: boolean }>() const emit = defineEmits<{ close: []; changed: [] }>() const tabs = [ + { key: 'channels' as const, label: 'Channels' }, { key: 'cashu' as const, label: 'Cashu Mints' }, { key: 'fedimint' as const, label: 'Fedimint Federations' }, ] -const activeTab = ref<'cashu' | 'fedimint'>('cashu') +const activeTab = ref<'channels' | 'cashu' | 'fedimint'>('channels') // Backed by wallet.fedimint-list / -join / -leave (fedimint-clientd HTTP bridge). // Join degrades gracefully with a clear error if the Fedimint client app isn't installed. diff --git a/neode-ui/src/views/apps/LightningChannels.vue b/neode-ui/src/views/apps/LightningChannels.vue index 307272e1..2e427ccb 100644 --- a/neode-ui/src/views/apps/LightningChannels.vue +++ b/neode-ui/src/views/apps/LightningChannels.vue @@ -10,321 +10,13 @@
Total Outbound
-{{ formatSats(summary.total_outbound) }}
-Total Inbound
-{{ formatSats(summary.total_inbound) }}
-Channels
-{{ channels.length }}
-Loading channels...
-{{ error }}
- -No channels yet
-Open a channel to start sending and receiving Lightning payments.
-- {{ ch.remote_pubkey }} -
- - -- Capacity: {{ formatSats(ch.capacity) }} -
-Format: pubkey@host:port
-Minimum 20,000 sats
-Some nodes (e.g. LSPs like Olympus) only accept unannounced channels
-{{ openError }}
-This will cooperatively close the channel with peer {{ closeTarget.remote_pubkey.slice(0, 16) }}...
-{{ closeError }}
-