1use std::collections::HashSet;
2use std::pin::Pin;
3
4use anyhow::Result;
5use serde_json::Value;
6use tokio::sync::{mpsc, watch};
7use tokio_stream::Stream;
8
9use sdk_common::prelude::*;
10
11use crate::{
12 bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey},
13 lightning_invoice::RawBolt11Invoice,
14 persist::error::PersistError,
15 CustomMessage, LnUrlAuthError, LspInformation, MaxChannelAmount, NodeCredentials, Payment,
16 PaymentResponse, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse,
17 RouteHint, RouteHintHop, SyncResponse, TlvEntry,
18};
19
20pub type NodeResult<T, E = NodeError> = Result<T, E>;
21
22#[derive(Debug, thiserror::Error)]
23pub enum NodeError {
24 #[error("{0}")]
25 Credentials(String),
26
27 #[error("{0}")]
28 Generic(String),
29
30 #[error(transparent)]
31 InvalidInvoice(#[from] InvoiceError),
32
33 #[error("{0}")]
34 InvoiceExpired(String),
35
36 #[error("{0}")]
37 InvoiceNoDescription(String),
38
39 #[error("{0}")]
40 InvoicePreimageAlreadyExists(String),
41
42 #[error("{0}")]
43 PaymentFailed(String),
44
45 #[error("{0}")]
46 PaymentTimeout(String),
47
48 #[error(transparent)]
49 Persistance(#[from] PersistError),
50
51 #[error("{0}")]
52 RestoreOnly(String),
53
54 #[error("{0}")]
55 RouteTooExpensive(String),
56
57 #[error("{0}")]
58 RouteNotFound(String),
59
60 #[error("{0}")]
61 ServiceConnectivity(String),
62
63 #[error("{0}")]
64 InsufficientFunds(String),
65
66 #[error("invoice already paid")]
67 InvoiceAlreadyPaid,
68}
69
70impl NodeError {
71 pub(crate) fn credentials(err: &str) -> Self {
72 Self::Credentials(err.to_string())
73 }
74
75 pub(crate) fn generic(err: &str) -> Self {
76 Self::Generic(err.to_string())
77 }
78}
79
80impl From<NodeError> for sdk_common::prelude::LnUrlError {
81 fn from(value: NodeError) -> Self {
82 match value {
83 NodeError::InvalidInvoice(err) => Self::InvalidInvoice(format!("{err}")),
84 NodeError::ServiceConnectivity(err) => Self::ServiceConnectivity(err),
85 _ => Self::Generic(value.to_string()),
86 }
87 }
88}
89
90impl From<NodeError> for LnUrlAuthError {
91 fn from(value: NodeError) -> Self {
92 match value {
93 NodeError::ServiceConnectivity(err) => Self::ServiceConnectivity { err },
94 _ => Self::Generic {
95 err: value.to_string(),
96 },
97 }
98 }
99}
100
101pub struct CreateInvoiceRequest {
102 pub amount_msat: u64,
103 pub description: String,
104 pub payer_amount_msat: Option<u64>,
105 pub preimage: Option<Vec<u8>>,
106 pub use_description_hash: Option<bool>,
107 pub expiry: Option<u32>,
108 pub cltv: Option<u32>,
109}
110
111pub struct FetchBolt11Result {
112 pub bolt11: String,
113 pub payer_amount_msat: Option<u64>,
114}
115
116#[cfg_attr(test, mockall::automock)]
118#[tonic::async_trait]
119pub trait NodeAPI: Send + Sync {
120 async fn node_credentials(&self) -> NodeResult<Option<NodeCredentials>>;
121 async fn configure_node(&self, close_to_address: Option<String>) -> NodeResult<()>;
122 async fn create_invoice(&self, request: CreateInvoiceRequest) -> NodeResult<String>;
123 async fn delete_invoice(&self, bolt11: String) -> NodeResult<()>;
124 async fn fetch_bolt11(&self, payment_hash: Vec<u8>) -> NodeResult<Option<FetchBolt11Result>>;
126 async fn pull_changed(
127 &self,
128 sync_state: Option<Value>,
129 match_local_balance: bool,
130 ) -> NodeResult<SyncResponse>;
131 async fn send_payment(
133 &self,
134 bolt11: String,
135 amount_msat: Option<u64>,
136 label: Option<String>,
137 ) -> NodeResult<Payment>;
138 async fn send_spontaneous_payment(
139 &self,
140 node_id: String,
141 amount_msat: u64,
142 extra_tlvs: Option<Vec<TlvEntry>>,
143 label: Option<String>,
144 ) -> NodeResult<Payment>;
145 async fn send_trampoline_payment(
146 &self,
147 bolt11: String,
148 amount_msat: u64,
149 label: Option<String>,
150 trampoline_node_id: Vec<u8>,
151 ) -> NodeResult<Payment>;
152 async fn node_id(&self) -> NodeResult<String>;
153
154 async fn send_pay(&self, bolt11: String, max_hops: u32) -> NodeResult<PaymentResponse>;
158
159 async fn max_sendable_amount<'a>(
161 &self,
162 payee_node_id: Option<Vec<u8>>,
163 max_hops: u32,
164 last_hop: Option<&'a RouteHintHop>,
165 ) -> NodeResult<Vec<MaxChannelAmount>>;
166 async fn redeem_onchain_funds(
167 &self,
168 to_address: String,
169 sat_per_vbyte: u32,
170 ) -> NodeResult<Vec<u8>>;
171 async fn prepare_redeem_onchain_funds(
172 &self,
173 req: PrepareRedeemOnchainFundsRequest,
174 ) -> NodeResult<PrepareRedeemOnchainFundsResponse>;
175 async fn start_signer(&self, shutdown: mpsc::Receiver<()>);
176 async fn start_keep_alive(&self, shutdown: watch::Receiver<()>);
177 async fn connect_peer(&self, node_id: String, addr: String) -> NodeResult<()>;
178 async fn sign_invoice(&self, invoice: RawBolt11Invoice) -> NodeResult<String>;
179 async fn close_peer_channels(&self, node_id: String) -> NodeResult<Vec<String>>;
180 async fn stream_incoming_payments(
181 &self,
182 ) -> NodeResult<Pin<Box<dyn Stream<Item = gl_client::signer::model::greenlight::IncomingPayment> + Send>>>;
183 async fn stream_log_messages(
184 &self,
185 ) -> NodeResult<Pin<Box<dyn Stream<Item = gl_client::signer::model::greenlight::LogEntry> + Send>>>;
186 async fn static_backup(&self) -> NodeResult<Vec<String>>;
187 async fn execute_command(&self, command: String) -> NodeResult<Value>;
188 async fn generate_diagnostic_data(&self) -> NodeResult<Value>;
189 async fn sign_message(&self, message: &str) -> NodeResult<String>;
190 async fn check_message(&self, message: &str, pubkey: &str, signature: &str)
191 -> NodeResult<bool>;
192 async fn send_custom_message(&self, message: CustomMessage) -> NodeResult<()>;
193 async fn stream_custom_messages(
194 &self,
195 ) -> NodeResult<Pin<Box<dyn Stream<Item = Result<CustomMessage>> + Send>>>;
196
197 async fn derive_bip32_key(&self, path: Vec<ChildNumber>) -> NodeResult<ExtendedPrivKey>;
199 async fn legacy_derive_bip32_key(&self, path: Vec<ChildNumber>) -> NodeResult<ExtendedPrivKey>;
200
201 async fn get_routing_hints(
204 &self,
205 lsp_info: &LspInformation,
206 ) -> NodeResult<(Vec<RouteHint>, bool)>;
207 async fn get_open_peers(&self) -> NodeResult<HashSet<Vec<u8>>>;
209}