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