diff --git a/ldk-server-cli/src/main.rs b/ldk-server-cli/src/main.rs index d960f087..ef2caebb 100644 --- a/ldk-server-cli/src/main.rs +++ b/ldk-server-cli/src/main.rs @@ -356,12 +356,15 @@ enum Commands { }, #[command(about = "Create a new outbound channel to the given remote node")] OpenChannel { - #[arg(help = "The hex-encoded public key of the node to open a channel with")] + #[arg( + help = "The peer to open a channel with in pubkey@address format, or just the pubkey if already connected or address is provided separately" + )] node_pubkey: String, #[arg( - help = "Address to connect to remote peer (IPv4:port, IPv6:port, OnionV3:port, or hostname:port)" + long, + help = "Address to connect to remote peer (IPv4:port, IPv6:port, OnionV3:port, or hostname:port). Optional if address is included in pubkey via @ separator or already connected." )] - address: String, + address: Option, #[arg( help = "The amount to commit to the channel, e.g. 100sat or 100000msat, must be a whole sat amount, cannot send msats on-chain." )] @@ -894,6 +897,13 @@ async fn main() { forwarding_fee_base_msat, cltv_expiry_delta, } => { + let (node_pubkey, address) = if let Some(address) = address { + (node_pubkey, Some(address)) + } else if let Some((pubkey, addr)) = node_pubkey.split_once('@') { + (pubkey.to_string(), Some(addr.to_string())) + } else { + (node_pubkey, None) + }; let channel_amount_sats = channel_amount.to_sat().unwrap_or_else(|e| handle_error_msg(&e)); let push_to_counterparty_msat = push_to_counterparty.map(|a| a.to_msat()); diff --git a/ldk-server-protos/src/api.rs b/ldk-server-protos/src/api.rs index f72357d3..80445f83 100644 --- a/ldk-server-protos/src/api.rs +++ b/ldk-server-protos/src/api.rs @@ -476,9 +476,10 @@ pub struct OpenChannelRequest { #[prost(string, tag = "1")] pub node_pubkey: ::prost::alloc::string::String, /// An address which can be used to connect to a remote peer. - /// It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - #[prost(string, tag = "2")] - pub address: ::prost::alloc::string::String, + /// It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port. + /// Optional if already connected to the peer. + #[prost(string, optional, tag = "2")] + pub address: ::core::option::Option<::prost::alloc::string::String>, /// The amount of satoshis the caller is willing to commit to the channel. #[prost(uint64, tag = "3")] pub channel_amount_sats: u64, diff --git a/ldk-server-protos/src/proto/api.proto b/ldk-server-protos/src/proto/api.proto index 3eb505d3..0fd93af3 100644 --- a/ldk-server-protos/src/proto/api.proto +++ b/ldk-server-protos/src/proto/api.proto @@ -393,8 +393,9 @@ message OpenChannelRequest { string node_pubkey = 1; // An address which can be used to connect to a remote peer. - // It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port - string address = 2; + // It can be of type IPv4:port, IPv6:port, OnionV3:port or hostname:port. + // Optional if already connected to the peer. + optional string address = 2; // The amount of satoshis the caller is willing to commit to the channel. uint64 channel_amount_sats = 3; diff --git a/ldk-server/src/api/open_channel.rs b/ldk-server/src/api/open_channel.rs index 6c470b71..a739aa6e 100644 --- a/ldk-server/src/api/open_channel.rs +++ b/ldk-server/src/api/open_channel.rs @@ -15,7 +15,7 @@ use ldk_node::lightning::ln::msgs::SocketAddress; use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse}; use crate::api::build_channel_config_from_proto; -use crate::api::error::LdkServerError; +use crate::api::error::{LdkServerError, LdkServerErrorCode}; use crate::service::Context; pub(crate) fn handle_open_channel( @@ -23,8 +23,23 @@ pub(crate) fn handle_open_channel( ) -> Result { let node_id = PublicKey::from_str(&request.node_pubkey) .map_err(|_| ldk_node::NodeError::InvalidPublicKey)?; - let address = SocketAddress::from_str(&request.address) - .map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?; + let address = match request.address { + Some(addr) => { + SocketAddress::from_str(&addr).map_err(|_| ldk_node::NodeError::InvalidSocketAddress)? + }, + None => context + .node + .list_peers() + .into_iter() + .find(|p| p.node_id == node_id && p.is_connected) + .map(|p| p.address) + .ok_or_else(|| { + LdkServerError::new( + LdkServerErrorCode::InvalidRequestError, + "address is required when not already connected to the peer", + ) + })?, + }; let channel_config = request .channel_config