浏览代码

feat: remove fedimint tonic lnd (#831)

* feat: remove fedimint tonic lnd
thesimplekid 1 月之前
父节点
当前提交
e016687d20

+ 2 - 4
Cargo.toml

@@ -93,14 +93,12 @@ instant = { version = "0.1", default-features = false }
 rand = "0.9.1"
 regex = "1"
 home = "0.5.5"
-tonic = { version = "0.13.1", features = [
-    "channel",
-    "tls-webpki-roots",
-] }
+tonic = { version = "0.13.1", features = ["tls-ring", "codegen", "prost", "transport"], default-features = false }
 prost = "0.13.1"
 tonic-build = "0.13.1"
 strum = "0.27.1"
 strum_macros = "0.27.1"
+rustls = { version = "0.23.28", default-features = false, features = ["ring"] }
 
 
 

+ 12 - 2
crates/cdk-lnd/Cargo.toml

@@ -14,10 +14,20 @@ readme = "README.md"
 async-trait.workspace = true
 anyhow.workspace = true
 cdk-common = { workspace = true, features = ["mint"] }
-fedimint-tonic-lnd = "0.2.0"
 futures.workspace = true
-tokio.workspace = true
+tokio = { workspace = true, default-features = false, features = ["fs"] }
 tokio-util.workspace = true
 tracing.workspace = true
 thiserror.workspace = true
 serde_json.workspace = true
+prost.workspace = true
+tonic = { workspace = true, features = ["transport"] }
+http = "1.3.1"
+hyper = { version = "1.6.0", features = ["http2", "client"] }
+hyper-util = { version = "0.1.14", features = ["client"] }
+hyper-rustls = { version = "0.27.7", features = ["http2", "tls12"] }
+rustls.workspace = true
+rustls-pemfile = "2.2.0"
+
+[build-dependencies]
+tonic-build.workspace = true

+ 19 - 0
crates/cdk-lnd/build.rs

@@ -0,0 +1,19 @@
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    println!("cargo:rerun-if-changed=src/proto/lnrpc.proto");
+    println!("cargo:rerun-if-changed=src/proto/routerrpc.proto");
+
+    // Tell cargo to tell rustc to allow missing docs in generated code
+    println!("cargo:rustc-env=RUSTDOC_ARGS=--allow-missing-docs");
+
+    // Configure tonic build to generate code with documentation
+    tonic_build::configure()
+        .protoc_arg("--experimental_allow_proto3_optional")
+        .type_attribute(".", "#[allow(missing_docs)]")
+        .field_attribute(".", "#[allow(missing_docs)]")
+        .compile_protos(
+            &["src/proto/lnrpc.proto", "src/proto/routerrpc.proto"],
+            &["src/proto"],
+        )?;
+
+    Ok(())
+}

+ 227 - 0
crates/cdk-lnd/src/client.rs

@@ -0,0 +1,227 @@
+//! GRPC Client
+
+use std::path::Path;
+use std::str::FromStr;
+use std::sync::Arc;
+
+use cdk_common::util::hex;
+use hyper_rustls::HttpsConnectorBuilder;
+use hyper_util::client::legacy::connect::HttpConnector;
+use hyper_util::client::legacy::Client as HyperClient;
+use hyper_util::rt::TokioExecutor;
+use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
+use rustls::crypto::ring::default_provider;
+use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
+use rustls::{ClientConfig, DigitallySignedStruct, Error as TLSError, SignatureScheme};
+use tokio::fs;
+use tonic::body::Body;
+use tonic::codegen::InterceptedService;
+use tonic::metadata::MetadataValue;
+use tonic::service::Interceptor;
+use tonic::{Request, Status};
+
+use crate::{lnrpc, routerrpc, Error};
+
+/// Custom certificate verifier for LND's self-signed certificates
+#[derive(Debug)]
+pub(crate) struct LndCertVerifier {
+    certs: Vec<Vec<u8>>,
+    provider: Arc<rustls::crypto::CryptoProvider>,
+}
+
+impl LndCertVerifier {
+    pub(crate) async fn load(path: impl AsRef<Path>) -> Result<Self, Error> {
+        let provider = default_provider();
+
+        let contents = fs::read(path).await.map_err(|_| Error::ReadFile)?;
+        let mut reader = std::io::Cursor::new(contents);
+
+        // Parse PEM certificates
+        let certs: Vec<CertificateDer<'static>> =
+            rustls_pemfile::certs(&mut reader).flatten().collect();
+
+        Ok(LndCertVerifier {
+            certs: certs.into_iter().map(|c| c.to_vec()).collect(),
+            provider: Arc::new(provider),
+        })
+    }
+}
+
+impl ServerCertVerifier for LndCertVerifier {
+    fn verify_server_cert(
+        &self,
+        end_entity: &CertificateDer<'_>,
+        intermediates: &[CertificateDer<'_>],
+        _server_name: &ServerName,
+        _ocsp_response: &[u8],
+        _now: UnixTime,
+    ) -> Result<ServerCertVerified, TLSError> {
+        let mut certs = intermediates
+            .iter()
+            .map(|c| c.as_ref().to_vec())
+            .collect::<Vec<Vec<u8>>>();
+        certs.push(end_entity.as_ref().to_vec());
+        certs.sort();
+
+        let mut our_certs = self.certs.clone();
+        our_certs.sort();
+
+        if self.certs.len() != certs.len() {
+            return Err(TLSError::General(format!(
+                "Mismatched number of certificates (Expected: {}, Presented: {})",
+                self.certs.len(),
+                certs.len()
+            )));
+        }
+        for (c, p) in our_certs.iter().zip(certs.iter()) {
+            if p != c {
+                return Err(TLSError::General(
+                    "Server certificates do not match ours".to_string(),
+                ));
+            }
+        }
+
+        Ok(ServerCertVerified::assertion())
+    }
+
+    fn verify_tls12_signature(
+        &self,
+        message: &[u8],
+        cert: &CertificateDer<'_>,
+        dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, TLSError> {
+        rustls::crypto::verify_tls12_signature(
+            message,
+            cert,
+            dss,
+            &self.provider.signature_verification_algorithms,
+        )
+        .map(|_| HandshakeSignatureValid::assertion())
+    }
+
+    fn verify_tls13_signature(
+        &self,
+        message: &[u8],
+        cert: &CertificateDer<'_>,
+        dss: &DigitallySignedStruct,
+    ) -> Result<HandshakeSignatureValid, TLSError> {
+        rustls::crypto::verify_tls13_signature(
+            message,
+            cert,
+            dss,
+            &self.provider.signature_verification_algorithms,
+        )
+        .map(|_| HandshakeSignatureValid::assertion())
+    }
+
+    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
+        self.provider
+            .signature_verification_algorithms
+            .supported_schemes()
+    }
+}
+
+pub type RouterClient = routerrpc::router_client::RouterClient<
+    InterceptedService<
+        HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Body>,
+        MacaroonInterceptor,
+    >,
+>;
+
+/// The client returned by `connect` function
+#[derive(Clone)]
+pub struct Client {
+    lightning: lnrpc::lightning_client::LightningClient<
+        InterceptedService<
+            HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Body>,
+            MacaroonInterceptor,
+        >,
+    >,
+    router: RouterClient,
+}
+
+/// Supplies requests with macaroon
+#[derive(Clone)]
+pub struct MacaroonInterceptor {
+    macaroon: String,
+}
+
+impl Interceptor for MacaroonInterceptor {
+    fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, Status> {
+        request.metadata_mut().insert(
+            "macaroon",
+            MetadataValue::from_str(&self.macaroon)
+                .map_err(|e| Status::internal(format!("Invalid macaroon: {e}")))?,
+        );
+        Ok(request)
+    }
+}
+
+async fn load_macaroon(path: impl AsRef<Path>) -> Result<String, Error> {
+    let macaroon = fs::read(path).await.map_err(|_| Error::ReadFile)?;
+    Ok(hex::encode(macaroon))
+}
+
+pub async fn connect<P: AsRef<Path>>(
+    address: &str,
+    cert_path: P,
+    macaroon_path: P,
+) -> Result<Client, Error> {
+    if rustls::crypto::CryptoProvider::get_default().is_none() {
+        let _ = rustls::crypto::ring::default_provider().install_default();
+    }
+
+    let config = ClientConfig::builder()
+        .dangerous()
+        .with_custom_certificate_verifier(Arc::new(LndCertVerifier::load(cert_path).await?))
+        .with_no_client_auth();
+
+    // Create HTTPS connector
+    let https = HttpsConnectorBuilder::new()
+        .with_tls_config(config)
+        .https_only()
+        .enable_http2()
+        .build();
+
+    // Create hyper client
+    let client = HyperClient::builder(TokioExecutor::new())
+        .http2_only(true)
+        .build(https);
+
+    // Load macaroon
+    let macaroon = load_macaroon(macaroon_path).await?;
+
+    // Create service with macaroon interceptor
+    let service = InterceptedService::new(client, MacaroonInterceptor { macaroon });
+
+    // Create URI for the service
+    let address = address
+        .trim_start_matches("http://")
+        .trim_start_matches("https://");
+    let uri = http::Uri::from_str(&format!("https://{address}"))
+        .map_err(|e| Error::InvalidConfig(format!("Invalid URI: {e}")))?;
+
+    // Create LND client
+    let lightning =
+        lnrpc::lightning_client::LightningClient::with_origin(service.clone(), uri.clone());
+    let router = RouterClient::with_origin(service, uri);
+
+    Ok(Client { lightning, router })
+}
+
+impl Client {
+    pub fn lightning(
+        &mut self,
+    ) -> &mut lnrpc::lightning_client::LightningClient<
+        InterceptedService<
+            HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Body>,
+            MacaroonInterceptor,
+        >,
+    > {
+        &mut self.lightning
+    }
+
+    pub fn router(&mut self) -> &mut RouterClient {
+        &mut self.router
+    }
+}

+ 10 - 1
crates/cdk-lnd/src/error.rs

@@ -1,7 +1,7 @@
 //! LND Errors
 
-use fedimint_tonic_lnd::tonic::Status;
 use thiserror::Error;
+use tonic::Status;
 
 /// LND Error
 #[derive(Debug, Error)]
@@ -36,6 +36,9 @@ pub enum Error {
     /// Errors invalid config
     #[error("LND invalid config: `{0}`")]
     InvalidConfig(String),
+    /// Could not read file
+    #[error("Could not read file")]
+    ReadFile,
 }
 
 impl From<Error> for cdk_common::payment::Error {
@@ -43,3 +46,9 @@ impl From<Error> for cdk_common::payment::Error {
         Self::Lightning(Box::new(e))
     }
 }
+
+impl From<tonic::transport::Error> for Error {
+    fn from(e: tonic::transport::Error) -> Self {
+        Error::InvalidConfig(format!("Transport error: {e}"))
+    }
+}

+ 50 - 63
crates/cdk-lnd/src/lib.rs

@@ -26,25 +26,26 @@ use cdk_common::payment::{
 use cdk_common::util::hex;
 use cdk_common::{mint, Bolt11Invoice};
 use error::Error;
-use fedimint_tonic_lnd::lnrpc::fee_limit::Limit;
-use fedimint_tonic_lnd::lnrpc::payment::PaymentStatus;
-use fedimint_tonic_lnd::lnrpc::{FeeLimit, Hop, MppRecord};
-use fedimint_tonic_lnd::tonic::Code;
-use fedimint_tonic_lnd::Client;
 use futures::{Stream, StreamExt};
-use tokio::sync::Mutex;
+use lnrpc::fee_limit::Limit;
+use lnrpc::payment::PaymentStatus;
+use lnrpc::{FeeLimit, Hop, MppRecord};
 use tokio_util::sync::CancellationToken;
 use tracing::instrument;
 
+mod client;
 pub mod error;
 
+mod proto;
+pub(crate) use proto::{lnrpc, routerrpc};
+
 /// Lnd mint backend
 #[derive(Clone)]
 pub struct Lnd {
-    address: String,
-    cert_file: PathBuf,
-    macaroon_file: PathBuf,
-    client: Arc<Mutex<Client>>,
+    _address: String,
+    _cert_file: PathBuf,
+    _macaroon_file: PathBuf,
+    lnd_client: client::Client,
     fee_reserve: FeeReserve,
     wait_invoice_cancel_token: CancellationToken,
     wait_invoice_is_active: Arc<AtomicBool>,
@@ -86,18 +87,19 @@ impl Lnd {
             )));
         }
 
-        let client = fedimint_tonic_lnd::connect(address.to_string(), &cert_file, &macaroon_file)
+        let lnd_client = client::connect(&address, &cert_file, &macaroon_file)
             .await
             .map_err(|err| {
                 tracing::error!("Connection error: {}", err.to_string());
                 Error::Connection
-            })?;
+            })
+            .unwrap();
 
         Ok(Self {
-            address,
-            cert_file,
-            macaroon_file,
-            client: Arc::new(Mutex::new(client)),
+            _address: address,
+            _cert_file: cert_file,
+            _macaroon_file: macaroon_file,
+            lnd_client,
             fee_reserve,
             wait_invoice_cancel_token: CancellationToken::new(),
             wait_invoice_is_active: Arc::new(AtomicBool::new(false)),
@@ -134,17 +136,14 @@ impl MintPayment for Lnd {
     async fn wait_any_incoming_payment(
         &self,
     ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> {
-        let mut client =
-            fedimint_tonic_lnd::connect(self.address.clone(), &self.cert_file, &self.macaroon_file)
-                .await
-                .map_err(|_| Error::Connection)?;
+        let mut lnd_client = self.lnd_client.clone();
 
-        let stream_req = fedimint_tonic_lnd::lnrpc::InvoiceSubscription {
+        let stream_req = lnrpc::InvoiceSubscription {
             add_index: 0,
             settle_index: 0,
         };
 
-        let stream = client
+        let stream = lnd_client
             .lightning()
             .subscribe_invoices(stream_req)
             .await
@@ -283,9 +282,11 @@ impl MintPayment for Lnd {
                 let payer_addr = invoice.payment_secret().0.to_vec();
                 let payment_hash = invoice.payment_hash();
 
+                let mut lnd_client = self.lnd_client.clone();
+
                 for attempt in 0..Self::MAX_ROUTE_RETRIES {
                     // Create a request for the routes
-                    let route_req = fedimint_tonic_lnd::lnrpc::QueryRoutesRequest {
+                    let route_req = lnrpc::QueryRoutesRequest {
                         pub_key: hex::encode(pub_key.serialize()),
                         amt_msat: u64::from(partial_amount_msat) as i64,
                         fee_limit: max_fee.map(|f| {
@@ -297,10 +298,7 @@ impl MintPayment for Lnd {
                     };
 
                     // Query the routes
-                    let mut routes_response: fedimint_tonic_lnd::lnrpc::QueryRoutesResponse = self
-                        .client
-                        .lock()
-                        .await
+                    let mut routes_response = lnd_client
                         .lightning()
                         .query_routes(route_req)
                         .await
@@ -319,12 +317,9 @@ impl MintPayment for Lnd {
                     };
                     last_hop.mpp_record = Some(mpp_record);
 
-                    let payment_response = self
-                        .client
-                        .lock()
-                        .await
+                    let payment_response = lnd_client
                         .router()
-                        .send_to_route_v2(fedimint_tonic_lnd::routerrpc::SendToRouteRequest {
+                        .send_to_route_v2(routerrpc::SendToRouteRequest {
                             payment_hash: payment_hash.to_byte_array().to_vec(),
                             route: Some(routes_response.routes[0].clone()),
                             ..Default::default()
@@ -375,23 +370,21 @@ impl MintPayment for Lnd {
                 Err(Error::PaymentFailed.into())
             }
             None => {
-                let pay_req = fedimint_tonic_lnd::lnrpc::SendRequest {
+                let mut lnd_client = self.lnd_client.clone();
+
+                let pay_req = lnrpc::SendRequest {
                     payment_request,
                     fee_limit: max_fee.map(|f| {
                         let limit = Limit::Fixed(u64::from(f) as i64);
-
                         FeeLimit { limit: Some(limit) }
                     }),
                     amt_msat: amount_msat as i64,
                     ..Default::default()
                 };
 
-                let payment_response = self
-                    .client
-                    .lock()
-                    .await
+                let payment_response = lnd_client
                     .lightning()
-                    .send_payment_sync(fedimint_tonic_lnd::tonic::Request::new(pay_req))
+                    .send_payment_sync(tonic::Request::new(pay_req))
                     .await
                     .map_err(|err| {
                         tracing::warn!("Lightning payment failed: {}", err);
@@ -433,20 +426,19 @@ impl MintPayment for Lnd {
     ) -> Result<CreateIncomingPaymentResponse, Self::Err> {
         let amount = to_unit(amount, unit, &CurrencyUnit::Msat)?;
 
-        let invoice_request = fedimint_tonic_lnd::lnrpc::Invoice {
+        let invoice_request = lnrpc::Invoice {
             value_msat: u64::from(amount) as i64,
             memo: description,
             ..Default::default()
         };
 
-        let invoice = self
-            .client
-            .lock()
-            .await
+        let mut lnd_client = self.lnd_client.clone();
+
+        let invoice = lnd_client
             .lightning()
-            .add_invoice(fedimint_tonic_lnd::tonic::Request::new(invoice_request))
+            .add_invoice(tonic::Request::new(invoice_request))
             .await
-            .unwrap()
+            .map_err(|e| payment::Error::Anyhow(anyhow!(e)))?
             .into_inner();
 
         let bolt11 = Bolt11Invoice::from_str(&invoice.payment_request)?;
@@ -463,19 +455,18 @@ impl MintPayment for Lnd {
         &self,
         request_lookup_id: &str,
     ) -> Result<MintQuoteState, Self::Err> {
-        let invoice_request = fedimint_tonic_lnd::lnrpc::PaymentHash {
+        let mut lnd_client = self.lnd_client.clone();
+
+        let invoice_request = lnrpc::PaymentHash {
             r_hash: hex::decode(request_lookup_id).unwrap(),
             ..Default::default()
         };
 
-        let invoice = self
-            .client
-            .lock()
-            .await
+        let invoice = lnd_client
             .lightning()
-            .lookup_invoice(fedimint_tonic_lnd::tonic::Request::new(invoice_request))
+            .lookup_invoice(tonic::Request::new(invoice_request))
             .await
-            .unwrap()
+            .map_err(|e| payment::Error::Anyhow(anyhow!(e)))?
             .into_inner();
 
         match invoice.state {
@@ -496,24 +487,20 @@ impl MintPayment for Lnd {
         &self,
         payment_hash: &str,
     ) -> Result<MakePaymentResponse, Self::Err> {
-        let track_request = fedimint_tonic_lnd::routerrpc::TrackPaymentRequest {
+        let mut lnd_client = self.lnd_client.clone();
+
+        let track_request = routerrpc::TrackPaymentRequest {
             payment_hash: hex::decode(payment_hash).map_err(|_| Error::InvalidHash)?,
             no_inflight_updates: true,
         };
 
-        let payment_response = self
-            .client
-            .lock()
-            .await
-            .router()
-            .track_payment_v2(track_request)
-            .await;
+        let payment_response = lnd_client.router().track_payment_v2(track_request).await;
 
         let mut payment_stream = match payment_response {
             Ok(stream) => stream.into_inner(),
             Err(err) => {
                 let err_code = err.code();
-                if err_code == Code::NotFound {
+                if err_code == tonic::Code::NotFound {
                     return Ok(MakePaymentResponse {
                         payment_lookup_id: payment_hash.to_string(),
                         payment_proof: None,
@@ -540,7 +527,7 @@ impl MintPayment for Lnd {
                             total_spent: Amount::ZERO,
                             unit: self.settings.unit.clone(),
                         },
-                        PaymentStatus::InFlight => {
+                        PaymentStatus::InFlight | PaymentStatus::Initiated => {
                             // Continue waiting for the next update
                             continue;
                         }

+ 5062 - 0
crates/cdk-lnd/src/proto/lnrpc.proto

@@ -0,0 +1,5062 @@
+syntax = "proto3";
+
+package lnrpc;
+
+option go_package = "github.com/lightningnetwork/lnd/lnrpc";
+
+/*
+ * Comments in this file will be directly parsed into the API
+ * Documentation as descriptions of the associated method, message, or field.
+ * These descriptions should go right above the definition of the object, and
+ * can be in either block or // comment format.
+ *
+ * An RPC method can be matched to an lncli command by placing a line in the
+ * beginning of the description in exactly the following format:
+ * lncli: `methodname`
+ *
+ * Failure to specify the exact name of the command will cause documentation
+ * generation to fail.
+ *
+ * More information on how exactly the gRPC documentation is generated from
+ * this proto file can be found here:
+ * https://github.com/lightninglabs/lightning-api
+ */
+
+// Lightning is the main RPC server of the daemon.
+service Lightning {
+    /* lncli: `walletbalance`
+    WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
+    confirmed unspent outputs and all unconfirmed unspent outputs under control
+    of the wallet.
+    */
+    rpc WalletBalance (WalletBalanceRequest) returns (WalletBalanceResponse);
+
+    /* lncli: `channelbalance`
+    ChannelBalance returns a report on the total funds across all open channels,
+    categorized in local/remote, pending local/remote and unsettled local/remote
+    balances.
+    */
+    rpc ChannelBalance (ChannelBalanceRequest) returns (ChannelBalanceResponse);
+
+    /* lncli: `listchaintxns`
+    GetTransactions returns a list describing all the known transactions
+    relevant to the wallet.
+    */
+    rpc GetTransactions (GetTransactionsRequest) returns (TransactionDetails);
+
+    /* lncli: `estimatefee`
+    EstimateFee asks the chain backend to estimate the fee rate and total fees
+    for a transaction that pays to multiple specified outputs.
+
+    When using REST, the `AddrToAmount` map type can be set by appending
+    `&AddrToAmount[<address>]=<amount_to_send>` to the URL. Unfortunately this
+    map type doesn't appear in the REST API documentation because of a bug in
+    the grpc-gateway library.
+    */
+    rpc EstimateFee (EstimateFeeRequest) returns (EstimateFeeResponse);
+
+    /* lncli: `sendcoins`
+    SendCoins executes a request to send coins to a particular address. Unlike
+    SendMany, this RPC call only allows creating a single output at a time. If
+    neither target_conf, or sat_per_vbyte are set, then the internal wallet will
+    consult its fee model to determine a fee for the default confirmation
+    target.
+    */
+    rpc SendCoins (SendCoinsRequest) returns (SendCoinsResponse);
+
+    /* lncli: `listunspent`
+    Deprecated, use walletrpc.ListUnspent instead.
+
+    ListUnspent returns a list of all utxos spendable by the wallet with a
+    number of confirmations between the specified minimum and maximum.
+    */
+    rpc ListUnspent (ListUnspentRequest) returns (ListUnspentResponse);
+
+    /*
+    SubscribeTransactions creates a uni-directional stream from the server to
+    the client in which any newly discovered transactions relevant to the
+    wallet are sent over.
+    */
+    rpc SubscribeTransactions (GetTransactionsRequest)
+        returns (stream Transaction);
+
+    /* lncli: `sendmany`
+    SendMany handles a request for a transaction that creates multiple specified
+    outputs in parallel. If neither target_conf, or sat_per_vbyte are set, then
+    the internal wallet will consult its fee model to determine a fee for the
+    default confirmation target.
+    */
+    rpc SendMany (SendManyRequest) returns (SendManyResponse);
+
+    /* lncli: `newaddress`
+    NewAddress creates a new address under control of the local wallet.
+    */
+    rpc NewAddress (NewAddressRequest) returns (NewAddressResponse);
+
+    /* lncli: `signmessage`
+    SignMessage signs a message with this node's private key. The returned
+    signature string is `zbase32` encoded and pubkey recoverable, meaning that
+    only the message digest and signature are needed for verification.
+    */
+    rpc SignMessage (SignMessageRequest) returns (SignMessageResponse);
+
+    /* lncli: `verifymessage`
+    VerifyMessage verifies a signature over a message and recovers the signer's
+    public key. The signature is only deemed valid if the recovered public key
+    corresponds to a node key in the public Lightning network. The signature
+    must be zbase32 encoded and signed by an active node in the resident node's
+    channel database. In addition to returning the validity of the signature,
+    VerifyMessage also returns the recovered pubkey from the signature.
+    */
+    rpc VerifyMessage (VerifyMessageRequest) returns (VerifyMessageResponse);
+
+    /* lncli: `connect`
+    ConnectPeer attempts to establish a connection to a remote peer. This is at
+    the networking level, and is used for communication between nodes. This is
+    distinct from establishing a channel with a peer.
+    */
+    rpc ConnectPeer (ConnectPeerRequest) returns (ConnectPeerResponse);
+
+    /* lncli: `disconnect`
+    DisconnectPeer attempts to disconnect one peer from another identified by a
+    given pubKey. In the case that we currently have a pending or active channel
+    with the target peer, then this action will be not be allowed.
+    */
+    rpc DisconnectPeer (DisconnectPeerRequest) returns (DisconnectPeerResponse);
+
+    /* lncli: `listpeers`
+    ListPeers returns a verbose listing of all currently active peers.
+    */
+    rpc ListPeers (ListPeersRequest) returns (ListPeersResponse);
+
+    /*
+    SubscribePeerEvents creates a uni-directional stream from the server to
+    the client in which any events relevant to the state of peers are sent
+    over. Events include peers going online and offline.
+    */
+    rpc SubscribePeerEvents (PeerEventSubscription) returns (stream PeerEvent);
+
+    /* lncli: `getinfo`
+    GetInfo returns general information concerning the lightning node including
+    it's identity pubkey, alias, the chains it is connected to, and information
+    concerning the number of open+pending channels.
+    */
+    rpc GetInfo (GetInfoRequest) returns (GetInfoResponse);
+
+    /* lncli: 'getdebuginfo'
+    GetDebugInfo returns debug information concerning the state of the daemon
+    and its subsystems. This includes the full configuration and the latest log
+    entries from the log file.
+    */
+    rpc GetDebugInfo (GetDebugInfoRequest) returns (GetDebugInfoResponse);
+
+    /** lncli: `getrecoveryinfo`
+    GetRecoveryInfo returns information concerning the recovery mode including
+    whether it's in a recovery mode, whether the recovery is finished, and the
+    progress made so far.
+    */
+    rpc GetRecoveryInfo (GetRecoveryInfoRequest)
+        returns (GetRecoveryInfoResponse);
+
+    // TODO(roasbeef): merge with below with bool?
+    /* lncli: `pendingchannels`
+    PendingChannels returns a list of all the channels that are currently
+    considered "pending". A channel is pending if it has finished the funding
+    workflow and is waiting for confirmations for the funding txn, or is in the
+    process of closure, either initiated cooperatively or non-cooperatively.
+    */
+    rpc PendingChannels (PendingChannelsRequest)
+        returns (PendingChannelsResponse);
+
+    /* lncli: `listchannels`
+    ListChannels returns a description of all the open channels that this node
+    is a participant in.
+    */
+    rpc ListChannels (ListChannelsRequest) returns (ListChannelsResponse);
+
+    /*
+    SubscribeChannelEvents creates a uni-directional stream from the server to
+    the client in which any updates relevant to the state of the channels are
+    sent over. Events include new active channels, inactive channels, and closed
+    channels.
+    */
+    rpc SubscribeChannelEvents (ChannelEventSubscription)
+        returns (stream ChannelEventUpdate);
+
+    /* lncli: `closedchannels`
+    ClosedChannels returns a description of all the closed channels that
+    this node was a participant in.
+    */
+    rpc ClosedChannels (ClosedChannelsRequest) returns (ClosedChannelsResponse);
+
+    /*
+    OpenChannelSync is a synchronous version of the OpenChannel RPC call. This
+    call is meant to be consumed by clients to the REST proxy. As with all
+    other sync calls, all byte slices are intended to be populated as hex
+    encoded strings.
+    */
+    rpc OpenChannelSync (OpenChannelRequest) returns (ChannelPoint);
+
+    /* lncli: `openchannel`
+    OpenChannel attempts to open a singly funded channel specified in the
+    request to a remote peer. Users are able to specify a target number of
+    blocks that the funding transaction should be confirmed in, or a manual fee
+    rate to us for the funding transaction. If neither are specified, then a
+    lax block confirmation target is used. Each OpenStatusUpdate will return
+    the pending channel ID of the in-progress channel. Depending on the
+    arguments specified in the OpenChannelRequest, this pending channel ID can
+    then be used to manually progress the channel funding flow.
+    */
+    rpc OpenChannel (OpenChannelRequest) returns (stream OpenStatusUpdate);
+
+    /* lncli: `batchopenchannel`
+    BatchOpenChannel attempts to open multiple single-funded channels in a
+    single transaction in an atomic way. This means either all channel open
+    requests succeed at once or all attempts are aborted if any of them fail.
+    This is the safer variant of using PSBTs to manually fund a batch of
+    channels through the OpenChannel RPC.
+    */
+    rpc BatchOpenChannel (BatchOpenChannelRequest)
+        returns (BatchOpenChannelResponse);
+
+    /*
+    FundingStateStep is an advanced funding related call that allows the caller
+    to either execute some preparatory steps for a funding workflow, or
+    manually progress a funding workflow. The primary way a funding flow is
+    identified is via its pending channel ID. As an example, this method can be
+    used to specify that we're expecting a funding flow for a particular
+    pending channel ID, for which we need to use specific parameters.
+    Alternatively, this can be used to interactively drive PSBT signing for
+    funding for partially complete funding transactions.
+    */
+    rpc FundingStateStep (FundingTransitionMsg) returns (FundingStateStepResp);
+
+    /*
+    ChannelAcceptor dispatches a bi-directional streaming RPC in which
+    OpenChannel requests are sent to the client and the client responds with
+    a boolean that tells LND whether or not to accept the channel. This allows
+    node operators to specify their own criteria for accepting inbound channels
+    through a single persistent connection.
+    */
+    rpc ChannelAcceptor (stream ChannelAcceptResponse)
+        returns (stream ChannelAcceptRequest);
+
+    /* lncli: `closechannel`
+    CloseChannel attempts to close an active channel identified by its channel
+    outpoint (ChannelPoint). The actions of this method can additionally be
+    augmented to attempt a force close after a timeout period in the case of an
+    inactive peer. If a non-force close (cooperative closure) is requested,
+    then the user can specify either a target number of blocks until the
+    closure transaction is confirmed, or a manual fee rate. If neither are
+    specified, then a default lax, block confirmation target is used.
+    */
+    rpc CloseChannel (CloseChannelRequest) returns (stream CloseStatusUpdate);
+
+    /* lncli: `abandonchannel`
+    AbandonChannel removes all channel state from the database except for a
+    close summary. This method can be used to get rid of permanently unusable
+    channels due to bugs fixed in newer versions of lnd. This method can also be
+    used to remove externally funded channels where the funding transaction was
+    never broadcast. Only available for non-externally funded channels in dev
+    build.
+    */
+    rpc AbandonChannel (AbandonChannelRequest) returns (AbandonChannelResponse);
+
+    /* lncli: `sendpayment`
+    Deprecated, use routerrpc.SendPaymentV2. SendPayment dispatches a
+    bi-directional streaming RPC for sending payments through the Lightning
+    Network. A single RPC invocation creates a persistent bi-directional
+    stream allowing clients to rapidly send payments through the Lightning
+    Network with a single persistent connection.
+    */
+    rpc SendPayment (stream SendRequest) returns (stream SendResponse) {
+        option deprecated = true;
+    }
+
+    /*
+    SendPaymentSync is the synchronous non-streaming version of SendPayment.
+    This RPC is intended to be consumed by clients of the REST proxy.
+    Additionally, this RPC expects the destination's public key and the payment
+    hash (if any) to be encoded as hex strings.
+    */
+    rpc SendPaymentSync (SendRequest) returns (SendResponse);
+
+    /* lncli: `sendtoroute`
+    Deprecated, use routerrpc.SendToRouteV2. SendToRoute is a bi-directional
+    streaming RPC for sending payment through the Lightning Network. This
+    method differs from SendPayment in that it allows users to specify a full
+    route manually. This can be used for things like rebalancing, and atomic
+    swaps.
+    */
+    rpc SendToRoute (stream SendToRouteRequest) returns (stream SendResponse) {
+        option deprecated = true;
+    }
+
+    /*
+    SendToRouteSync is a synchronous version of SendToRoute. It Will block
+    until the payment either fails or succeeds.
+    */
+    rpc SendToRouteSync (SendToRouteRequest) returns (SendResponse);
+
+    /* lncli: `addinvoice`
+    AddInvoice attempts to add a new invoice to the invoice database. Any
+    duplicated invoices are rejected, therefore all invoices *must* have a
+    unique payment preimage.
+    */
+    rpc AddInvoice (Invoice) returns (AddInvoiceResponse);
+
+    /* lncli: `listinvoices`
+    ListInvoices returns a list of all the invoices currently stored within the
+    database. Any active debug invoices are ignored. It has full support for
+    paginated responses, allowing users to query for specific invoices through
+    their add_index. This can be done by using either the first_index_offset or
+    last_index_offset fields included in the response as the index_offset of the
+    next request. By default, the first 100 invoices created will be returned.
+    Backwards pagination is also supported through the Reversed flag.
+    */
+    rpc ListInvoices (ListInvoiceRequest) returns (ListInvoiceResponse);
+
+    /* lncli: `lookupinvoice`
+    LookupInvoice attempts to look up an invoice according to its payment hash.
+    The passed payment hash *must* be exactly 32 bytes, if not, an error is
+    returned.
+    */
+    rpc LookupInvoice (PaymentHash) returns (Invoice);
+
+    /*
+    SubscribeInvoices returns a uni-directional stream (server -> client) for
+    notifying the client of newly added/settled invoices. The caller can
+    optionally specify the add_index and/or the settle_index. If the add_index
+    is specified, then we'll first start by sending add invoice events for all
+    invoices with an add_index greater than the specified value. If the
+    settle_index is specified, then next, we'll send out all settle events for
+    invoices with a settle_index greater than the specified value. One or both
+    of these fields can be set. If no fields are set, then we'll only send out
+    the latest add/settle events.
+    */
+    rpc SubscribeInvoices (InvoiceSubscription) returns (stream Invoice);
+
+    /* lncli: `decodepayreq`
+    DecodePayReq takes an encoded payment request string and attempts to decode
+    it, returning a full description of the conditions encoded within the
+    payment request.
+    */
+    rpc DecodePayReq (PayReqString) returns (PayReq);
+
+    /* lncli: `listpayments`
+    ListPayments returns a list of all outgoing payments.
+    */
+    rpc ListPayments (ListPaymentsRequest) returns (ListPaymentsResponse);
+
+    /* lncli: `deletepayments`
+    DeletePayment deletes an outgoing payment from DB. Note that it will not
+    attempt to delete an In-Flight payment, since that would be unsafe.
+    */
+    rpc DeletePayment (DeletePaymentRequest) returns (DeletePaymentResponse);
+
+    /* lncli: `deletepayments --all`
+    DeleteAllPayments deletes all outgoing payments from DB. Note that it will
+    not attempt to delete In-Flight payments, since that would be unsafe.
+    */
+    rpc DeleteAllPayments (DeleteAllPaymentsRequest)
+        returns (DeleteAllPaymentsResponse);
+
+    /* lncli: `describegraph`
+    DescribeGraph returns a description of the latest graph state from the
+    point of view of the node. The graph information is partitioned into two
+    components: all the nodes/vertexes, and all the edges that connect the
+    vertices themselves. As this is a directed graph, the edges also contain
+    the node directional specific routing policy which includes: the time lock
+    delta, fee information, etc.
+    */
+    rpc DescribeGraph (ChannelGraphRequest) returns (ChannelGraph);
+
+    /* lncli: `getnodemetrics`
+    GetNodeMetrics returns node metrics calculated from the graph. Currently
+    the only supported metric is betweenness centrality of individual nodes.
+    */
+    rpc GetNodeMetrics (NodeMetricsRequest) returns (NodeMetricsResponse);
+
+    /* lncli: `getchaninfo`
+    GetChanInfo returns the latest authenticated network announcement for the
+    given channel identified by its channel ID: an 8-byte integer which
+    uniquely identifies the location of transaction's funding output within the
+    blockchain.
+    */
+    rpc GetChanInfo (ChanInfoRequest) returns (ChannelEdge);
+
+    /* lncli: `getnodeinfo`
+    GetNodeInfo returns the latest advertised, aggregated, and authenticated
+    channel information for the specified node identified by its public key.
+    */
+    rpc GetNodeInfo (NodeInfoRequest) returns (NodeInfo);
+
+    /* lncli: `queryroutes`
+    QueryRoutes attempts to query the daemon's Channel Router for a possible
+    route to a target destination capable of carrying a specific amount of
+    satoshis. The returned route contains the full details required to craft and
+    send an HTLC, also including the necessary information that should be
+    present within the Sphinx packet encapsulated within the HTLC.
+
+    When using REST, the `dest_custom_records` map type can be set by appending
+    `&dest_custom_records[<record_number>]=<record_data_base64_url_encoded>`
+    to the URL. Unfortunately this map type doesn't appear in the REST API
+    documentation because of a bug in the grpc-gateway library.
+    */
+    rpc QueryRoutes (QueryRoutesRequest) returns (QueryRoutesResponse);
+
+    /* lncli: `getnetworkinfo`
+    GetNetworkInfo returns some basic stats about the known channel graph from
+    the point of view of the node.
+    */
+    rpc GetNetworkInfo (NetworkInfoRequest) returns (NetworkInfo);
+
+    /* lncli: `stop`
+    StopDaemon will send a shutdown request to the interrupt handler, triggering
+    a graceful shutdown of the daemon.
+    */
+    rpc StopDaemon (StopRequest) returns (StopResponse);
+
+    /*
+    SubscribeChannelGraph launches a streaming RPC that allows the caller to
+    receive notifications upon any changes to the channel graph topology from
+    the point of view of the responding node. Events notified include: new
+    nodes coming online, nodes updating their authenticated attributes, new
+    channels being advertised, updates in the routing policy for a directional
+    channel edge, and when channels are closed on-chain.
+    */
+    rpc SubscribeChannelGraph (GraphTopologySubscription)
+        returns (stream GraphTopologyUpdate);
+
+    /* lncli: `debuglevel`
+    DebugLevel allows a caller to programmatically set the logging verbosity of
+    lnd. The logging can be targeted according to a coarse daemon-wide logging
+    level, or in a granular fashion to specify the logging for a target
+    sub-system.
+    */
+    rpc DebugLevel (DebugLevelRequest) returns (DebugLevelResponse);
+
+    /* lncli: `feereport`
+    FeeReport allows the caller to obtain a report detailing the current fee
+    schedule enforced by the node globally for each channel.
+    */
+    rpc FeeReport (FeeReportRequest) returns (FeeReportResponse);
+
+    /* lncli: `updatechanpolicy`
+    UpdateChannelPolicy allows the caller to update the fee schedule and
+    channel policies for all channels globally, or a particular channel.
+    */
+    rpc UpdateChannelPolicy (PolicyUpdateRequest)
+        returns (PolicyUpdateResponse);
+
+    /* lncli: `fwdinghistory`
+    ForwardingHistory allows the caller to query the htlcswitch for a record of
+    all HTLCs forwarded within the target time range, and integer offset
+    within that time range, for a maximum number of events. If no maximum number
+    of events is specified, up to 100 events will be returned. If no time-range
+    is specified, then events will be returned in the order that they occurred.
+
+    A list of forwarding events are returned. The size of each forwarding event
+    is 40 bytes, and the max message size able to be returned in gRPC is 4 MiB.
+    As a result each message can only contain 50k entries. Each response has
+    the index offset of the last entry. The index offset can be provided to the
+    request to allow the caller to skip a series of records.
+    */
+    rpc ForwardingHistory (ForwardingHistoryRequest)
+        returns (ForwardingHistoryResponse);
+
+    /* lncli: `exportchanbackup`
+    ExportChannelBackup attempts to return an encrypted static channel backup
+    for the target channel identified by it channel point. The backup is
+    encrypted with a key generated from the aezeed seed of the user. The
+    returned backup can either be restored using the RestoreChannelBackup
+    method once lnd is running, or via the InitWallet and UnlockWallet methods
+    from the WalletUnlocker service.
+    */
+    rpc ExportChannelBackup (ExportChannelBackupRequest)
+        returns (ChannelBackup);
+
+    /*
+    ExportAllChannelBackups returns static channel backups for all existing
+    channels known to lnd. A set of regular singular static channel backups for
+    each channel are returned. Additionally, a multi-channel backup is returned
+    as well, which contains a single encrypted blob containing the backups of
+    each channel.
+    */
+    rpc ExportAllChannelBackups (ChanBackupExportRequest)
+        returns (ChanBackupSnapshot);
+
+    /* lncli: `verifychanbackup`
+    VerifyChanBackup allows a caller to verify the integrity of a channel backup
+    snapshot. This method will accept either a packed Single or a packed Multi.
+    Specifying both will result in an error.
+    */
+    rpc VerifyChanBackup (ChanBackupSnapshot)
+        returns (VerifyChanBackupResponse);
+
+    /* lncli: `restorechanbackup`
+    RestoreChannelBackups accepts a set of singular channel backups, or a
+    single encrypted multi-chan backup and attempts to recover any funds
+    remaining within the channel. If we are able to unpack the backup, then the
+    new channel will be shown under listchannels, as well as pending channels.
+    */
+    rpc RestoreChannelBackups (RestoreChanBackupRequest)
+        returns (RestoreBackupResponse);
+
+    /*
+    SubscribeChannelBackups allows a client to sub-subscribe to the most up to
+    date information concerning the state of all channel backups. Each time a
+    new channel is added, we return the new set of channels, along with a
+    multi-chan backup containing the backup info for all channels. Each time a
+    channel is closed, we send a new update, which contains new new chan back
+    ups, but the updated set of encrypted multi-chan backups with the closed
+    channel(s) removed.
+    */
+    rpc SubscribeChannelBackups (ChannelBackupSubscription)
+        returns (stream ChanBackupSnapshot);
+
+    /* lncli: `bakemacaroon`
+    BakeMacaroon allows the creation of a new macaroon with custom read and
+    write permissions. No first-party caveats are added since this can be done
+    offline.
+    */
+    rpc BakeMacaroon (BakeMacaroonRequest) returns (BakeMacaroonResponse);
+
+    /* lncli: `listmacaroonids`
+    ListMacaroonIDs returns all root key IDs that are in use.
+    */
+    rpc ListMacaroonIDs (ListMacaroonIDsRequest)
+        returns (ListMacaroonIDsResponse);
+
+    /* lncli: `deletemacaroonid`
+    DeleteMacaroonID deletes the specified macaroon ID and invalidates all
+    macaroons derived from that ID.
+    */
+    rpc DeleteMacaroonID (DeleteMacaroonIDRequest)
+        returns (DeleteMacaroonIDResponse);
+
+    /* lncli: `listpermissions`
+    ListPermissions lists all RPC method URIs and their required macaroon
+    permissions to access them.
+    */
+    rpc ListPermissions (ListPermissionsRequest)
+        returns (ListPermissionsResponse);
+
+    /*
+    CheckMacaroonPermissions checks whether a request follows the constraints
+    imposed on the macaroon and that the macaroon is authorized to follow the
+    provided permissions.
+    */
+    rpc CheckMacaroonPermissions (CheckMacPermRequest)
+        returns (CheckMacPermResponse);
+
+    /*
+    RegisterRPCMiddleware adds a new gRPC middleware to the interceptor chain. A
+    gRPC middleware is software component external to lnd that aims to add
+    additional business logic to lnd by observing/intercepting/validating
+    incoming gRPC client requests and (if needed) replacing/overwriting outgoing
+    messages before they're sent to the client. When registering the middleware
+    must identify itself and indicate what custom macaroon caveats it wants to
+    be responsible for. Only requests that contain a macaroon with that specific
+    custom caveat are then sent to the middleware for inspection. The other
+    option is to register for the read-only mode in which all requests/responses
+    are forwarded for interception to the middleware but the middleware is not
+    allowed to modify any responses. As a security measure, _no_ middleware can
+    modify responses for requests made with _unencumbered_ macaroons!
+    */
+    rpc RegisterRPCMiddleware (stream RPCMiddlewareResponse)
+        returns (stream RPCMiddlewareRequest);
+
+    /* lncli: `sendcustom`
+    SendCustomMessage sends a custom peer message.
+    */
+    rpc SendCustomMessage (SendCustomMessageRequest)
+        returns (SendCustomMessageResponse);
+
+    /* lncli: `subscribecustom`
+    SubscribeCustomMessages subscribes to a stream of incoming custom peer
+    messages.
+
+    To include messages with type outside of the custom range (>= 32768) lnd
+    needs to be compiled with  the `dev` build tag, and the message type to
+    override should be specified in lnd's experimental protocol configuration.
+    */
+    rpc SubscribeCustomMessages (SubscribeCustomMessagesRequest)
+        returns (stream CustomMessage);
+
+    /* lncli: `listaliases`
+    ListAliases returns the set of all aliases that have ever existed with
+    their confirmed SCID (if it exists) and/or the base SCID (in the case of
+    zero conf).
+    */
+    rpc ListAliases (ListAliasesRequest) returns (ListAliasesResponse);
+
+    /*
+    LookupHtlcResolution retrieves a final htlc resolution from the database.
+    If the htlc has no final resolution yet, a NotFound grpc status code is
+    returned.
+    */
+    rpc LookupHtlcResolution (LookupHtlcResolutionRequest)
+        returns (LookupHtlcResolutionResponse);
+}
+
+message LookupHtlcResolutionRequest {
+    uint64 chan_id = 1;
+
+    uint64 htlc_index = 2;
+}
+
+message LookupHtlcResolutionResponse {
+    // Settled is true is the htlc was settled. If false, the htlc was failed.
+    bool settled = 1;
+
+    // Offchain indicates whether the htlc was resolved off-chain or on-chain.
+    bool offchain = 2;
+}
+
+message SubscribeCustomMessagesRequest {
+}
+
+message CustomMessage {
+    // Peer from which the message originates
+    bytes peer = 1;
+
+    // Message type. This value will be in the custom range (>= 32768).
+    uint32 type = 2;
+
+    // Raw message data
+    bytes data = 3;
+}
+
+message SendCustomMessageRequest {
+    // Peer to send the message to
+    bytes peer = 1;
+
+    // Message type. This value needs to be in the custom range (>= 32768).
+    // To send a type < custom range, lnd needs to be compiled with the `dev`
+    // build tag, and the message type to override should be specified in lnd's
+    // experimental protocol configuration.
+    uint32 type = 2;
+
+    // Raw message data.
+    bytes data = 3;
+}
+
+message SendCustomMessageResponse {
+}
+
+message Utxo {
+    // The type of address
+    AddressType address_type = 1;
+
+    // The address
+    string address = 2;
+
+    // The value of the unspent coin in satoshis
+    int64 amount_sat = 3;
+
+    // The pkscript in hex
+    string pk_script = 4;
+
+    // The outpoint in format txid:n
+    OutPoint outpoint = 5;
+
+    // The number of confirmations for the Utxo
+    int64 confirmations = 6;
+}
+
+enum OutputScriptType {
+    SCRIPT_TYPE_PUBKEY_HASH = 0;
+    SCRIPT_TYPE_SCRIPT_HASH = 1;
+    SCRIPT_TYPE_WITNESS_V0_PUBKEY_HASH = 2;
+    SCRIPT_TYPE_WITNESS_V0_SCRIPT_HASH = 3;
+    SCRIPT_TYPE_PUBKEY = 4;
+    SCRIPT_TYPE_MULTISIG = 5;
+    SCRIPT_TYPE_NULLDATA = 6;
+    SCRIPT_TYPE_NON_STANDARD = 7;
+    SCRIPT_TYPE_WITNESS_UNKNOWN = 8;
+    SCRIPT_TYPE_WITNESS_V1_TAPROOT = 9;
+}
+
+message OutputDetail {
+    // The type of the output
+    OutputScriptType output_type = 1;
+
+    // The address
+    string address = 2;
+
+    // The pkscript in hex
+    string pk_script = 3;
+
+    // The output index used in the raw transaction
+    int64 output_index = 4;
+
+    // The value of the output coin in satoshis
+    int64 amount = 5;
+
+    // Denotes if the output is controlled by the internal wallet
+    bool is_our_address = 6;
+}
+
+message Transaction {
+    // The transaction hash
+    string tx_hash = 1;
+
+    // The transaction amount, denominated in satoshis
+    int64 amount = 2;
+
+    // The number of confirmations
+    int32 num_confirmations = 3;
+
+    // The hash of the block this transaction was included in
+    string block_hash = 4;
+
+    // The height of the block this transaction was included in
+    int32 block_height = 5;
+
+    // Timestamp of this transaction
+    int64 time_stamp = 6;
+
+    // Fees paid for this transaction
+    int64 total_fees = 7;
+
+    // Addresses that received funds for this transaction. Deprecated as it is
+    // now incorporated in the output_details field.
+    repeated string dest_addresses = 8 [deprecated = true];
+
+    // Outputs that received funds for this transaction
+    repeated OutputDetail output_details = 11;
+
+    // The raw transaction hex.
+    string raw_tx_hex = 9;
+
+    // A label that was optionally set on transaction broadcast.
+    string label = 10;
+
+    // PreviousOutpoints/Inputs of this transaction.
+    repeated PreviousOutPoint previous_outpoints = 12;
+}
+
+message GetTransactionsRequest {
+    /*
+    The height from which to list transactions, inclusive. If this value is
+    greater than end_height, transactions will be read in reverse.
+    */
+    int32 start_height = 1;
+
+    /*
+    The height until which to list transactions, inclusive. To include
+    unconfirmed transactions, this value should be set to -1, which will
+    return transactions from start_height until the current chain tip and
+    unconfirmed transactions. If no end_height is provided, the call will
+    default to this option.
+    */
+    int32 end_height = 2;
+
+    // An optional filter to only include transactions relevant to an account.
+    string account = 3;
+}
+
+message TransactionDetails {
+    // The list of transactions relevant to the wallet.
+    repeated Transaction transactions = 1;
+}
+
+message FeeLimit {
+    oneof limit {
+        /*
+        The fee limit expressed as a fixed amount of satoshis.
+
+        The fields fixed and fixed_msat are mutually exclusive.
+        */
+        int64 fixed = 1;
+
+        /*
+        The fee limit expressed as a fixed amount of millisatoshis.
+
+        The fields fixed and fixed_msat are mutually exclusive.
+        */
+        int64 fixed_msat = 3;
+
+        // The fee limit expressed as a percentage of the payment amount.
+        int64 percent = 2;
+    }
+}
+
+message SendRequest {
+    /*
+    The identity pubkey of the payment recipient. When using REST, this field
+    must be encoded as base64.
+    */
+    bytes dest = 1;
+
+    /*
+    The hex-encoded identity pubkey of the payment recipient. Deprecated now
+    that the REST gateway supports base64 encoding of bytes fields.
+    */
+    string dest_string = 2 [deprecated = true];
+
+    /*
+    The amount to send expressed in satoshis.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt = 3;
+
+    /*
+    The amount to send expressed in millisatoshis.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt_msat = 12;
+
+    /*
+    The hash to use within the payment's HTLC. When using REST, this field
+    must be encoded as base64.
+    */
+    bytes payment_hash = 4;
+
+    /*
+    The hex-encoded hash to use within the payment's HTLC. Deprecated now
+    that the REST gateway supports base64 encoding of bytes fields.
+    */
+    string payment_hash_string = 5 [deprecated = true];
+
+    /*
+    A bare-bones invoice for a payment within the Lightning Network. With the
+    details of the invoice, the sender has all the data necessary to send a
+    payment to the recipient.
+    */
+    string payment_request = 6;
+
+    /*
+    The CLTV delta from the current height that should be used to set the
+    timelock for the final hop.
+    */
+    int32 final_cltv_delta = 7;
+
+    /*
+    The maximum number of satoshis that will be paid as a fee of the payment.
+    This value can be represented either as a percentage of the amount being
+    sent, or as a fixed amount of the maximum fee the user is willing the pay to
+    send the payment. If not specified, lnd will use a default value of 100%
+    fees for small amounts (<=1k sat) or 5% fees for larger amounts.
+    */
+    FeeLimit fee_limit = 8;
+
+    /*
+    The channel id of the channel that must be taken to the first hop. If zero,
+    any channel may be used.
+    */
+    uint64 outgoing_chan_id = 9 [jstype = JS_STRING];
+
+    /*
+    The pubkey of the last hop of the route. If empty, any hop may be used.
+    */
+    bytes last_hop_pubkey = 13;
+
+    /*
+    An optional maximum total time lock for the route. This should not exceed
+    lnd's `--max-cltv-expiry` setting. If zero, then the value of
+    `--max-cltv-expiry` is enforced.
+    */
+    uint32 cltv_limit = 10;
+
+    /*
+    An optional field that can be used to pass an arbitrary set of TLV records
+    to a peer which understands the new records. This can be used to pass
+    application specific data during the payment attempt. Record types are
+    required to be in the custom range >= 65536. When using REST, the values
+    must be encoded as base64.
+    */
+    map<uint64, bytes> dest_custom_records = 11;
+
+    // If set, circular payments to self are permitted.
+    bool allow_self_payment = 14;
+
+    /*
+    Features assumed to be supported by the final node. All transitive feature
+    dependencies must also be set properly. For a given feature bit pair, either
+    optional or remote may be set, but not both. If this field is nil or empty,
+    the router will try to load destination features from the graph as a
+    fallback.
+    */
+    repeated FeatureBit dest_features = 15;
+
+    /*
+    The payment address of the generated invoice.  This is also called
+    payment secret in specifications (e.g. BOLT 11).
+    */
+    bytes payment_addr = 16;
+}
+
+message SendResponse {
+    string payment_error = 1;
+    bytes payment_preimage = 2;
+    Route payment_route = 3;
+    bytes payment_hash = 4;
+}
+
+message SendToRouteRequest {
+    /*
+    The payment hash to use for the HTLC. When using REST, this field must be
+    encoded as base64.
+    */
+    bytes payment_hash = 1;
+
+    /*
+    An optional hex-encoded payment hash to be used for the HTLC. Deprecated now
+    that the REST gateway supports base64 encoding of bytes fields.
+    */
+    string payment_hash_string = 2 [deprecated = true];
+
+    reserved 3;
+
+    // Route that should be used to attempt to complete the payment.
+    Route route = 4;
+}
+
+message ChannelAcceptRequest {
+    // The pubkey of the node that wishes to open an inbound channel.
+    bytes node_pubkey = 1;
+
+    // The hash of the genesis block that the proposed channel resides in.
+    bytes chain_hash = 2;
+
+    // The pending channel id.
+    bytes pending_chan_id = 3;
+
+    // The funding amount in satoshis that initiator wishes to use in the
+    // channel.
+    uint64 funding_amt = 4;
+
+    // The push amount of the proposed channel in millisatoshis.
+    uint64 push_amt = 5;
+
+    // The dust limit of the initiator's commitment tx.
+    uint64 dust_limit = 6;
+
+    // The maximum amount of coins in millisatoshis that can be pending in this
+    // channel.
+    uint64 max_value_in_flight = 7;
+
+    // The minimum amount of satoshis the initiator requires us to have at all
+    // times.
+    uint64 channel_reserve = 8;
+
+    // The smallest HTLC in millisatoshis that the initiator will accept.
+    uint64 min_htlc = 9;
+
+    // The initial fee rate that the initiator suggests for both commitment
+    // transactions.
+    uint64 fee_per_kw = 10;
+
+    /*
+    The number of blocks to use for the relative time lock in the pay-to-self
+    output of both commitment transactions.
+    */
+    uint32 csv_delay = 11;
+
+    // The total number of incoming HTLC's that the initiator will accept.
+    uint32 max_accepted_htlcs = 12;
+
+    // A bit-field which the initiator uses to specify proposed channel
+    // behavior.
+    uint32 channel_flags = 13;
+
+    // The commitment type the initiator wishes to use for the proposed channel.
+    CommitmentType commitment_type = 14;
+
+    // Whether the initiator wants to open a zero-conf channel via the channel
+    // type.
+    bool wants_zero_conf = 15;
+
+    // Whether the initiator wants to use the scid-alias channel type. This is
+    // separate from the feature bit.
+    bool wants_scid_alias = 16;
+}
+
+message ChannelAcceptResponse {
+    // Whether or not the client accepts the channel.
+    bool accept = 1;
+
+    // The pending channel id to which this response applies.
+    bytes pending_chan_id = 2;
+
+    /*
+    An optional error to send the initiating party to indicate why the channel
+    was rejected. This field *should not* contain sensitive information, it will
+    be sent to the initiating party. This field should only be set if accept is
+    false, the channel will be rejected if an error is set with accept=true
+    because the meaning of this response is ambiguous. Limited to 500
+    characters.
+    */
+    string error = 3;
+
+    /*
+    The upfront shutdown address to use if the initiating peer supports option
+    upfront shutdown script (see ListPeers for the features supported). Note
+    that the channel open will fail if this value is set for a peer that does
+    not support this feature bit.
+    */
+    string upfront_shutdown = 4;
+
+    /*
+    The csv delay (in blocks) that we require for the remote party.
+    */
+    uint32 csv_delay = 5;
+
+    /*
+    The reserve amount in satoshis that we require the remote peer to adhere to.
+    We require that the remote peer always have some reserve amount allocated to
+    them so that there is always a disincentive to broadcast old state (if they
+    hold 0 sats on their side of the channel, there is nothing to lose).
+    */
+    uint64 reserve_sat = 6;
+
+    /*
+    The maximum amount of funds in millisatoshis that we allow the remote peer
+    to have in outstanding htlcs.
+    */
+    uint64 in_flight_max_msat = 7;
+
+    /*
+    The maximum number of htlcs that the remote peer can offer us.
+    */
+    uint32 max_htlc_count = 8;
+
+    /*
+    The minimum value in millisatoshis for incoming htlcs on the channel.
+    */
+    uint64 min_htlc_in = 9;
+
+    /*
+    The number of confirmations we require before we consider the channel open.
+    */
+    uint32 min_accept_depth = 10;
+
+    /*
+    Whether the responder wants this to be a zero-conf channel. This will fail
+    if either side does not have the scid-alias feature bit set. The minimum
+    depth field must be zero if this is true.
+    */
+    bool zero_conf = 11;
+}
+
+message ChannelPoint {
+    oneof funding_txid {
+        /*
+        Txid of the funding transaction. When using REST, this field must be
+        encoded as base64.
+        */
+        bytes funding_txid_bytes = 1;
+
+        /*
+        Hex-encoded string representing the byte-reversed hash of the funding
+        transaction.
+        */
+        string funding_txid_str = 2;
+    }
+
+    // The index of the output of the funding transaction
+    uint32 output_index = 3;
+}
+
+message OutPoint {
+    // Raw bytes representing the transaction id.
+    bytes txid_bytes = 1;
+
+    // Reversed, hex-encoded string representing the transaction id.
+    string txid_str = 2;
+
+    // The index of the output on the transaction.
+    uint32 output_index = 3;
+}
+
+message PreviousOutPoint {
+    // The outpoint in format txid:n.
+    string outpoint = 1;
+
+    // Denotes if the outpoint is controlled by the internal wallet.
+    // The flag will only detect p2wkh, np2wkh and p2tr inputs as its own.
+    bool is_our_output = 2;
+}
+
+message LightningAddress {
+    // The identity pubkey of the Lightning node.
+    string pubkey = 1;
+
+    // The network location of the lightning node, e.g. `69.69.69.69:1337` or
+    // `localhost:10011`.
+    string host = 2;
+}
+
+enum CoinSelectionStrategy {
+    // Use the coin selection strategy defined in the global configuration
+    // (lnd.conf).
+    STRATEGY_USE_GLOBAL_CONFIG = 0;
+
+    // Select the largest available coins first during coin selection.
+    STRATEGY_LARGEST = 1;
+
+    // Randomly select the available coins during coin selection.
+    STRATEGY_RANDOM = 2;
+}
+
+message EstimateFeeRequest {
+    // The map from addresses to amounts for the transaction.
+    map<string, int64> AddrToAmount = 1;
+
+    // The target number of blocks that this transaction should be confirmed
+    // by.
+    int32 target_conf = 2;
+
+    // The minimum number of confirmations each one of your outputs used for
+    // the transaction must satisfy.
+    int32 min_confs = 3;
+
+    // Whether unconfirmed outputs should be used as inputs for the transaction.
+    bool spend_unconfirmed = 4;
+
+    // The strategy to use for selecting coins during fees estimation.
+    CoinSelectionStrategy coin_selection_strategy = 5;
+}
+
+message EstimateFeeResponse {
+    // The total fee in satoshis.
+    int64 fee_sat = 1;
+
+    // Deprecated, use sat_per_vbyte.
+    // The fee rate in satoshi/vbyte.
+    int64 feerate_sat_per_byte = 2 [deprecated = true];
+
+    // The fee rate in satoshi/vbyte.
+    uint64 sat_per_vbyte = 3;
+}
+
+message SendManyRequest {
+    // The map from addresses to amounts
+    map<string, int64> AddrToAmount = 1;
+
+    // The target number of blocks that this transaction should be confirmed
+    // by.
+    int32 target_conf = 3;
+
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // transaction.
+    uint64 sat_per_vbyte = 4;
+
+    // Deprecated, use sat_per_vbyte.
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // transaction.
+    int64 sat_per_byte = 5 [deprecated = true];
+
+    // An optional label for the transaction, limited to 500 characters.
+    string label = 6;
+
+    // The minimum number of confirmations each one of your outputs used for
+    // the transaction must satisfy.
+    int32 min_confs = 7;
+
+    // Whether unconfirmed outputs should be used as inputs for the transaction.
+    bool spend_unconfirmed = 8;
+
+    // The strategy to use for selecting coins during sending many requests.
+    CoinSelectionStrategy coin_selection_strategy = 9;
+}
+message SendManyResponse {
+    // The id of the transaction
+    string txid = 1;
+}
+
+message SendCoinsRequest {
+    // The address to send coins to
+    string addr = 1;
+
+    // The amount in satoshis to send
+    int64 amount = 2;
+
+    // The target number of blocks that this transaction should be confirmed
+    // by.
+    int32 target_conf = 3;
+
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // transaction.
+    uint64 sat_per_vbyte = 4;
+
+    // Deprecated, use sat_per_vbyte.
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // transaction.
+    int64 sat_per_byte = 5 [deprecated = true];
+
+    /*
+    If set, then the amount field will be ignored, and lnd will attempt to
+    send all the coins under control of the internal wallet to the specified
+    address.
+    */
+    bool send_all = 6;
+
+    // An optional label for the transaction, limited to 500 characters.
+    string label = 7;
+
+    // The minimum number of confirmations each one of your outputs used for
+    // the transaction must satisfy.
+    int32 min_confs = 8;
+
+    // Whether unconfirmed outputs should be used as inputs for the transaction.
+    bool spend_unconfirmed = 9;
+
+    // The strategy to use for selecting coins.
+    CoinSelectionStrategy coin_selection_strategy = 10;
+}
+message SendCoinsResponse {
+    // The transaction ID of the transaction
+    string txid = 1;
+}
+
+message ListUnspentRequest {
+    // The minimum number of confirmations to be included.
+    int32 min_confs = 1;
+
+    // The maximum number of confirmations to be included.
+    int32 max_confs = 2;
+
+    // An optional filter to only include outputs belonging to an account.
+    string account = 3;
+}
+message ListUnspentResponse {
+    // A list of utxos
+    repeated Utxo utxos = 1;
+}
+
+/*
+`AddressType` has to be one of:
+
+- `p2wkh`: Pay to witness key hash (`WITNESS_PUBKEY_HASH` = 0)
+- `np2wkh`: Pay to nested witness key hash (`NESTED_PUBKEY_HASH` = 1)
+- `p2tr`: Pay to taproot pubkey (`TAPROOT_PUBKEY` = 4)
+*/
+enum AddressType {
+    WITNESS_PUBKEY_HASH = 0;
+    NESTED_PUBKEY_HASH = 1;
+    UNUSED_WITNESS_PUBKEY_HASH = 2;
+    UNUSED_NESTED_PUBKEY_HASH = 3;
+    TAPROOT_PUBKEY = 4;
+    UNUSED_TAPROOT_PUBKEY = 5;
+}
+
+message NewAddressRequest {
+    // The type of address to generate.
+    AddressType type = 1;
+
+    /*
+    The name of the account to generate a new address for. If empty, the
+    default wallet account is used.
+    */
+    string account = 2;
+}
+message NewAddressResponse {
+    // The newly generated wallet address
+    string address = 1;
+}
+
+message SignMessageRequest {
+    /*
+    The message to be signed. When using REST, this field must be encoded as
+    base64.
+    */
+    bytes msg = 1;
+
+    /*
+    Instead of the default double-SHA256 hashing of the message before signing,
+    only use one round of hashing instead.
+    */
+    bool single_hash = 2;
+}
+message SignMessageResponse {
+    // The signature for the given message
+    string signature = 1;
+}
+
+message VerifyMessageRequest {
+    /*
+    The message over which the signature is to be verified. When using REST,
+    this field must be encoded as base64.
+    */
+    bytes msg = 1;
+
+    // The signature to be verified over the given message
+    string signature = 2;
+}
+message VerifyMessageResponse {
+    // Whether the signature was valid over the given message
+    bool valid = 1;
+
+    // The pubkey recovered from the signature
+    string pubkey = 2;
+}
+
+message ConnectPeerRequest {
+    /*
+    Lightning address of the peer to connect to.
+    */
+    LightningAddress addr = 1;
+
+    /*
+    If set, the daemon will attempt to persistently connect to the target
+    peer. Otherwise, the call will be synchronous.
+    */
+    bool perm = 2;
+
+    /*
+    The connection timeout value (in seconds) for this request. It won't affect
+    other requests.
+    */
+    uint64 timeout = 3;
+}
+message ConnectPeerResponse {
+}
+
+message DisconnectPeerRequest {
+    // The pubkey of the node to disconnect from
+    string pub_key = 1;
+}
+message DisconnectPeerResponse {
+}
+
+message HTLC {
+    bool incoming = 1;
+    int64 amount = 2;
+    bytes hash_lock = 3;
+    uint32 expiration_height = 4;
+
+    // Index identifying the htlc on the channel.
+    uint64 htlc_index = 5;
+
+    // If this HTLC is involved in a forwarding operation, this field indicates
+    // the forwarding channel. For an outgoing htlc, it is the incoming channel.
+    // For an incoming htlc, it is the outgoing channel. When the htlc
+    // originates from this node or this node is the final destination,
+    // forwarding_channel will be zero. The forwarding channel will also be zero
+    // for htlcs that need to be forwarded but don't have a forwarding decision
+    // persisted yet.
+    uint64 forwarding_channel = 6;
+
+    // Index identifying the htlc on the forwarding channel.
+    uint64 forwarding_htlc_index = 7;
+}
+
+enum CommitmentType {
+    /*
+    Returned when the commitment type isn't known or unavailable.
+    */
+    UNKNOWN_COMMITMENT_TYPE = 0;
+
+    /*
+    A channel using the legacy commitment format having tweaked to_remote
+    keys.
+    */
+    LEGACY = 1;
+
+    /*
+    A channel that uses the modern commitment format where the key in the
+    output of the remote party does not change each state. This makes back
+    up and recovery easier as when the channel is closed, the funds go
+    directly to that key.
+    */
+    STATIC_REMOTE_KEY = 2;
+
+    /*
+    A channel that uses a commitment format that has anchor outputs on the
+    commitments, allowing fee bumping after a force close transaction has
+    been broadcast.
+    */
+    ANCHORS = 3;
+
+    /*
+    A channel that uses a commitment type that builds upon the anchors
+    commitment format, but in addition requires a CLTV clause to spend outputs
+    paying to the channel initiator. This is intended for use on leased channels
+    to guarantee that the channel initiator has no incentives to close a leased
+    channel before its maturity date.
+    */
+    SCRIPT_ENFORCED_LEASE = 4;
+
+    /*
+    A channel that uses musig2 for the funding output, and the new tapscript
+    features where relevant.
+    */
+    // TODO(roasbeef): need script enforce mirror type for the above as well?
+    SIMPLE_TAPROOT = 5;
+}
+
+message ChannelConstraints {
+    /*
+    The CSV delay expressed in relative blocks. If the channel is force closed,
+    we will need to wait for this many blocks before we can regain our funds.
+    */
+    uint32 csv_delay = 1;
+
+    // The minimum satoshis this node is required to reserve in its balance.
+    uint64 chan_reserve_sat = 2;
+
+    // The dust limit (in satoshis) of the initiator's commitment tx.
+    uint64 dust_limit_sat = 3;
+
+    // The maximum amount of coins in millisatoshis that can be pending in this
+    // channel.
+    uint64 max_pending_amt_msat = 4;
+
+    // The smallest HTLC in millisatoshis that the initiator will accept.
+    uint64 min_htlc_msat = 5;
+
+    // The total number of incoming HTLC's that the initiator will accept.
+    uint32 max_accepted_htlcs = 6;
+}
+
+message Channel {
+    // Whether this channel is active or not
+    bool active = 1;
+
+    // The identity pubkey of the remote node
+    string remote_pubkey = 2;
+
+    /*
+    The outpoint (txid:index) of the funding transaction. With this value, Bob
+    will be able to generate a signature for Alice's version of the commitment
+    transaction.
+    */
+    string channel_point = 3;
+
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 chan_id = 4 [jstype = JS_STRING];
+
+    // The total amount of funds held in this channel
+    int64 capacity = 5;
+
+    // This node's current balance in this channel
+    int64 local_balance = 6;
+
+    // The counterparty's current balance in this channel
+    int64 remote_balance = 7;
+
+    /*
+    The amount calculated to be paid in fees for the current set of commitment
+    transactions. The fee amount is persisted with the channel in order to
+    allow the fee amount to be removed and recalculated with each channel state
+    update, including updates that happen after a system restart.
+    */
+    int64 commit_fee = 8;
+
+    // The weight of the commitment transaction
+    int64 commit_weight = 9;
+
+    /*
+    The required number of satoshis per kilo-weight that the requester will pay
+    at all times, for both the funding transaction and commitment transaction.
+    This value can later be updated once the channel is open.
+    */
+    int64 fee_per_kw = 10;
+
+    // The unsettled balance in this channel
+    int64 unsettled_balance = 11;
+
+    /*
+    The total number of satoshis we've sent within this channel.
+    */
+    int64 total_satoshis_sent = 12;
+
+    /*
+    The total number of satoshis we've received within this channel.
+    */
+    int64 total_satoshis_received = 13;
+
+    /*
+    The total number of updates conducted within this channel.
+    */
+    uint64 num_updates = 14;
+
+    /*
+    The list of active, uncleared HTLCs currently pending within the channel.
+    */
+    repeated HTLC pending_htlcs = 15;
+
+    /*
+    Deprecated. The CSV delay expressed in relative blocks. If the channel is
+    force closed, we will need to wait for this many blocks before we can regain
+    our funds.
+    */
+    uint32 csv_delay = 16 [deprecated = true];
+
+    // Whether this channel is advertised to the network or not.
+    bool private = 17;
+
+    // True if we were the ones that created the channel.
+    bool initiator = 18;
+
+    // A set of flags showing the current state of the channel.
+    string chan_status_flags = 19;
+
+    // Deprecated. The minimum satoshis this node is required to reserve in its
+    // balance.
+    int64 local_chan_reserve_sat = 20 [deprecated = true];
+
+    /*
+    Deprecated. The minimum satoshis the other node is required to reserve in
+    its balance.
+    */
+    int64 remote_chan_reserve_sat = 21 [deprecated = true];
+
+    // Deprecated. Use commitment_type.
+    bool static_remote_key = 22 [deprecated = true];
+
+    // The commitment type used by this channel.
+    CommitmentType commitment_type = 26;
+
+    /*
+    The number of seconds that the channel has been monitored by the channel
+    scoring system. Scores are currently not persisted, so this value may be
+    less than the lifetime of the channel [EXPERIMENTAL].
+    */
+    int64 lifetime = 23;
+
+    /*
+    The number of seconds that the remote peer has been observed as being online
+    by the channel scoring system over the lifetime of the channel
+    [EXPERIMENTAL].
+    */
+    int64 uptime = 24;
+
+    /*
+    Close address is the address that we will enforce payout to on cooperative
+    close if the channel was opened utilizing option upfront shutdown. This
+    value can be set on channel open by setting close_address in an open channel
+    request. If this value is not set, you can still choose a payout address by
+    cooperatively closing with the delivery_address field set.
+    */
+    string close_address = 25;
+
+    /*
+    The amount that the initiator of the channel optionally pushed to the remote
+    party on channel open. This amount will be zero if the channel initiator did
+    not push any funds to the remote peer. If the initiator field is true, we
+    pushed this amount to our peer, if it is false, the remote peer pushed this
+    amount to us.
+    */
+    uint64 push_amount_sat = 27;
+
+    /*
+    This uint32 indicates if this channel is to be considered 'frozen'. A
+    frozen channel doest not allow a cooperative channel close by the
+    initiator. The thaw_height is the height that this restriction stops
+    applying to the channel. This field is optional, not setting it or using a
+    value of zero will mean the channel has no additional restrictions. The
+    height can be interpreted in two ways: as a relative height if the value is
+    less than 500,000, or as an absolute height otherwise.
+    */
+    uint32 thaw_height = 28;
+
+    // List constraints for the local node.
+    ChannelConstraints local_constraints = 29;
+
+    // List constraints for the remote node.
+    ChannelConstraints remote_constraints = 30;
+
+    /*
+    This lists out the set of alias short channel ids that exist for a channel.
+    This may be empty.
+    */
+    repeated uint64 alias_scids = 31;
+
+    // Whether or not this is a zero-conf channel.
+    bool zero_conf = 32;
+
+    // This is the confirmed / on-chain zero-conf SCID.
+    uint64 zero_conf_confirmed_scid = 33;
+
+    // The configured alias name of our peer.
+    string peer_alias = 34;
+
+    // This is the peer SCID alias.
+    uint64 peer_scid_alias = 35 [jstype = JS_STRING];
+
+    /*
+    An optional note-to-self to go along with the channel containing some
+    useful information. This is only ever stored locally and in no way impacts
+    the channel's operation.
+    */
+    string memo = 36;
+}
+
+message ListChannelsRequest {
+    bool active_only = 1;
+    bool inactive_only = 2;
+    bool public_only = 3;
+    bool private_only = 4;
+
+    /*
+    Filters the response for channels with a target peer's pubkey. If peer is
+    empty, all channels will be returned.
+    */
+    bytes peer = 5;
+
+    // Informs the server if the peer alias lookup per channel should be
+    // enabled. It is turned off by default in order to avoid degradation of
+    // performance for existing clients.
+    bool peer_alias_lookup = 6;
+}
+message ListChannelsResponse {
+    // The list of active channels
+    repeated Channel channels = 11;
+}
+
+message AliasMap {
+    /*
+    For non-zero-conf channels, this is the confirmed SCID. Otherwise, this is
+    the first assigned "base" alias.
+    */
+    uint64 base_scid = 1;
+
+    // The set of all aliases stored for the base SCID.
+    repeated uint64 aliases = 2;
+}
+message ListAliasesRequest {
+}
+message ListAliasesResponse {
+    repeated AliasMap alias_maps = 1;
+}
+
+enum Initiator {
+    INITIATOR_UNKNOWN = 0;
+    INITIATOR_LOCAL = 1;
+    INITIATOR_REMOTE = 2;
+    INITIATOR_BOTH = 3;
+}
+
+message ChannelCloseSummary {
+    // The outpoint (txid:index) of the funding transaction.
+    string channel_point = 1;
+
+    //  The unique channel ID for the channel.
+    uint64 chan_id = 2 [jstype = JS_STRING];
+
+    // The hash of the genesis block that this channel resides within.
+    string chain_hash = 3;
+
+    // The txid of the transaction which ultimately closed this channel.
+    string closing_tx_hash = 4;
+
+    // Public key of the remote peer that we formerly had a channel with.
+    string remote_pubkey = 5;
+
+    // Total capacity of the channel.
+    int64 capacity = 6;
+
+    // Height at which the funding transaction was spent.
+    uint32 close_height = 7;
+
+    // Settled balance at the time of channel closure
+    int64 settled_balance = 8;
+
+    // The sum of all the time-locked outputs at the time of channel closure
+    int64 time_locked_balance = 9;
+
+    enum ClosureType {
+        COOPERATIVE_CLOSE = 0;
+        LOCAL_FORCE_CLOSE = 1;
+        REMOTE_FORCE_CLOSE = 2;
+        BREACH_CLOSE = 3;
+        FUNDING_CANCELED = 4;
+        ABANDONED = 5;
+    }
+
+    // Details on how the channel was closed.
+    ClosureType close_type = 10;
+
+    /*
+    Open initiator is the party that initiated opening the channel. Note that
+    this value may be unknown if the channel was closed before we migrated to
+    store open channel information after close.
+    */
+    Initiator open_initiator = 11;
+
+    /*
+    Close initiator indicates which party initiated the close. This value will
+    be unknown for channels that were cooperatively closed before we started
+    tracking cooperative close initiators. Note that this indicates which party
+    initiated a close, and it is possible for both to initiate cooperative or
+    force closes, although only one party's close will be confirmed on chain.
+    */
+    Initiator close_initiator = 12;
+
+    repeated Resolution resolutions = 13;
+
+    /*
+    This lists out the set of alias short channel ids that existed for the
+    closed channel. This may be empty.
+    */
+    repeated uint64 alias_scids = 14;
+
+    //  The confirmed SCID for a zero-conf channel.
+    uint64 zero_conf_confirmed_scid = 15 [jstype = JS_STRING];
+}
+
+enum ResolutionType {
+    TYPE_UNKNOWN = 0;
+
+    // We resolved an anchor output.
+    ANCHOR = 1;
+
+    /*
+    We are resolving an incoming htlc on chain. This if this htlc is
+    claimed, we swept the incoming htlc with the preimage. If it is timed
+    out, our peer swept the timeout path.
+    */
+    INCOMING_HTLC = 2;
+
+    /*
+    We are resolving an outgoing htlc on chain. If this htlc is claimed,
+    the remote party swept the htlc with the preimage. If it is timed out,
+    we swept it with the timeout path.
+    */
+    OUTGOING_HTLC = 3;
+
+    // We force closed and need to sweep our time locked commitment output.
+    COMMIT = 4;
+}
+
+enum ResolutionOutcome {
+    // Outcome unknown.
+    OUTCOME_UNKNOWN = 0;
+
+    // An output was claimed on chain.
+    CLAIMED = 1;
+
+    // An output was left unclaimed on chain.
+    UNCLAIMED = 2;
+
+    /*
+    ResolverOutcomeAbandoned indicates that an output that we did not
+    claim on chain, for example an anchor that we did not sweep and a
+    third party claimed on chain, or a htlc that we could not decode
+    so left unclaimed.
+    */
+    ABANDONED = 3;
+
+    /*
+    If we force closed our channel, our htlcs need to be claimed in two
+    stages. This outcome represents the broadcast of a timeout or success
+    transaction for this two stage htlc claim.
+    */
+    FIRST_STAGE = 4;
+
+    // A htlc was timed out on chain.
+    TIMEOUT = 5;
+}
+
+message Resolution {
+    // The type of output we are resolving.
+    ResolutionType resolution_type = 1;
+
+    // The outcome of our on chain action that resolved the outpoint.
+    ResolutionOutcome outcome = 2;
+
+    // The outpoint that was spent by the resolution.
+    OutPoint outpoint = 3;
+
+    // The amount that was claimed by the resolution.
+    uint64 amount_sat = 4;
+
+    // The hex-encoded transaction ID of the sweep transaction that spent the
+    // output.
+    string sweep_txid = 5;
+}
+
+message ClosedChannelsRequest {
+    bool cooperative = 1;
+    bool local_force = 2;
+    bool remote_force = 3;
+    bool breach = 4;
+    bool funding_canceled = 5;
+    bool abandoned = 6;
+}
+
+message ClosedChannelsResponse {
+    repeated ChannelCloseSummary channels = 1;
+}
+
+message Peer {
+    // The identity pubkey of the peer
+    string pub_key = 1;
+
+    // Network address of the peer; eg `127.0.0.1:10011`
+    string address = 3;
+
+    // Bytes of data transmitted to this peer
+    uint64 bytes_sent = 4;
+
+    // Bytes of data transmitted from this peer
+    uint64 bytes_recv = 5;
+
+    // Satoshis sent to this peer
+    int64 sat_sent = 6;
+
+    // Satoshis received from this peer
+    int64 sat_recv = 7;
+
+    // A channel is inbound if the counterparty initiated the channel
+    bool inbound = 8;
+
+    // Ping time to this peer
+    int64 ping_time = 9;
+
+    enum SyncType {
+        /*
+        Denotes that we cannot determine the peer's current sync type.
+        */
+        UNKNOWN_SYNC = 0;
+
+        /*
+        Denotes that we are actively receiving new graph updates from the peer.
+        */
+        ACTIVE_SYNC = 1;
+
+        /*
+        Denotes that we are not receiving new graph updates from the peer.
+        */
+        PASSIVE_SYNC = 2;
+
+        /*
+        Denotes that this peer is pinned into an active sync.
+        */
+        PINNED_SYNC = 3;
+    }
+
+    // The type of sync we are currently performing with this peer.
+    SyncType sync_type = 10;
+
+    // Features advertised by the remote peer in their init message.
+    map<uint32, Feature> features = 11;
+
+    /*
+    The latest errors received from our peer with timestamps, limited to the 10
+    most recent errors. These errors are tracked across peer connections, but
+    are not persisted across lnd restarts. Note that these errors are only
+    stored for peers that we have channels open with, to prevent peers from
+    spamming us with errors at no cost.
+    */
+    repeated TimestampedError errors = 12;
+
+    /*
+    The number of times we have recorded this peer going offline or coming
+    online, recorded across restarts. Note that this value is decreased over
+    time if the peer has not recently flapped, so that we can forgive peers
+    with historically high flap counts.
+    */
+    int32 flap_count = 13;
+
+    /*
+    The timestamp of the last flap we observed for this peer. If this value is
+    zero, we have not observed any flaps for this peer.
+    */
+    int64 last_flap_ns = 14;
+
+    /*
+    The last ping payload the peer has sent to us.
+    */
+    bytes last_ping_payload = 15;
+}
+
+message TimestampedError {
+    // The unix timestamp in seconds when the error occurred.
+    uint64 timestamp = 1;
+
+    // The string representation of the error sent by our peer.
+    string error = 2;
+}
+
+message ListPeersRequest {
+    /*
+    If true, only the last error that our peer sent us will be returned with
+    the peer's information, rather than the full set of historic errors we have
+    stored.
+    */
+    bool latest_error = 1;
+}
+message ListPeersResponse {
+    // The list of currently connected peers
+    repeated Peer peers = 1;
+}
+
+message PeerEventSubscription {
+}
+
+message PeerEvent {
+    // The identity pubkey of the peer.
+    string pub_key = 1;
+
+    enum EventType {
+        PEER_ONLINE = 0;
+        PEER_OFFLINE = 1;
+    }
+
+    EventType type = 2;
+}
+
+message GetInfoRequest {
+}
+message GetInfoResponse {
+    // The version of the LND software that the node is running.
+    string version = 14;
+
+    // The SHA1 commit hash that the daemon is compiled with.
+    string commit_hash = 20;
+
+    // The identity pubkey of the current node.
+    string identity_pubkey = 1;
+
+    // If applicable, the alias of the current node, e.g. "bob"
+    string alias = 2;
+
+    // The color of the current node in hex code format
+    string color = 17;
+
+    // Number of pending channels
+    uint32 num_pending_channels = 3;
+
+    // Number of active channels
+    uint32 num_active_channels = 4;
+
+    // Number of inactive channels
+    uint32 num_inactive_channels = 15;
+
+    // Number of peers
+    uint32 num_peers = 5;
+
+    // The node's current view of the height of the best block
+    uint32 block_height = 6;
+
+    // The node's current view of the hash of the best block
+    string block_hash = 8;
+
+    // Timestamp of the block best known to the wallet
+    int64 best_header_timestamp = 13;
+
+    // Whether the wallet's view is synced to the main chain
+    bool synced_to_chain = 9;
+
+    // Whether we consider ourselves synced with the public channel graph.
+    bool synced_to_graph = 18;
+
+    /*
+    Whether the current node is connected to testnet. This field is
+    deprecated and the network field should be used instead
+    */
+    bool testnet = 10 [deprecated = true];
+
+    reserved 11;
+
+    /*
+    A list of active chains the node is connected to. This will only
+    ever contain a single entry since LND will only ever have a single
+    chain backend during its lifetime.
+    */
+    repeated Chain chains = 16;
+
+    // The URIs of the current node.
+    repeated string uris = 12;
+
+    /*
+    Features that our node has advertised in our init message, node
+    announcements and invoices.
+    */
+    map<uint32, Feature> features = 19;
+
+    /*
+    Indicates whether the HTLC interceptor API is in always-on mode.
+    */
+    bool require_htlc_interceptor = 21;
+
+    // Indicates whether final htlc resolutions are stored on disk.
+    bool store_final_htlc_resolutions = 22;
+}
+
+message GetDebugInfoRequest {
+}
+
+message GetDebugInfoResponse {
+    map<string, string> config = 1;
+    repeated string log = 2;
+}
+
+message GetRecoveryInfoRequest {
+}
+message GetRecoveryInfoResponse {
+    // Whether the wallet is in recovery mode
+    bool recovery_mode = 1;
+
+    // Whether the wallet recovery progress is finished
+    bool recovery_finished = 2;
+
+    // The recovery progress, ranging from 0 to 1.
+    double progress = 3;
+}
+
+message Chain {
+    // Deprecated. The chain is now always assumed to be bitcoin.
+    // The blockchain the node is on (must be bitcoin)
+    string chain = 1 [deprecated = true];
+
+    // The network the node is on (eg regtest, testnet, mainnet)
+    string network = 2;
+}
+
+message ConfirmationUpdate {
+    bytes block_sha = 1;
+    int32 block_height = 2;
+
+    uint32 num_confs_left = 3;
+}
+
+message ChannelOpenUpdate {
+    ChannelPoint channel_point = 1;
+}
+
+message ChannelCloseUpdate {
+    bytes closing_txid = 1;
+
+    bool success = 2;
+}
+
+message CloseChannelRequest {
+    /*
+    The outpoint (txid:index) of the funding transaction. With this value, Bob
+    will be able to generate a signature for Alice's version of the commitment
+    transaction.
+    */
+    ChannelPoint channel_point = 1;
+
+    // If true, then the channel will be closed forcibly. This means the
+    // current commitment transaction will be signed and broadcast.
+    bool force = 2;
+
+    // The target number of blocks that the closure transaction should be
+    // confirmed by.
+    int32 target_conf = 3;
+
+    // Deprecated, use sat_per_vbyte.
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // closure transaction.
+    int64 sat_per_byte = 4 [deprecated = true];
+
+    /*
+    An optional address to send funds to in the case of a cooperative close.
+    If the channel was opened with an upfront shutdown script and this field
+    is set, the request to close will fail because the channel must pay out
+    to the upfront shutdown address.
+    */
+    string delivery_address = 5;
+
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // closure transaction.
+    uint64 sat_per_vbyte = 6;
+
+    // The maximum fee rate the closer is willing to pay.
+    //
+    // NOTE: This field is only respected if we're the initiator of the channel.
+    uint64 max_fee_per_vbyte = 7;
+
+    // If true, then the rpc call will not block while it awaits a closing txid.
+    // Consequently this RPC call will not return a closing txid if this value
+    // is set.
+    bool no_wait = 8;
+}
+
+message CloseStatusUpdate {
+    oneof update {
+        PendingUpdate close_pending = 1;
+        ChannelCloseUpdate chan_close = 3;
+        InstantUpdate close_instant = 4;
+    }
+}
+
+message PendingUpdate {
+    bytes txid = 1;
+    uint32 output_index = 2;
+}
+
+message InstantUpdate {
+}
+
+message ReadyForPsbtFunding {
+    /*
+    The P2WSH address of the channel funding multisig address that the below
+    specified amount in satoshis needs to be sent to.
+    */
+    string funding_address = 1;
+
+    /*
+    The exact amount in satoshis that needs to be sent to the above address to
+    fund the pending channel.
+    */
+    int64 funding_amount = 2;
+
+    /*
+    A raw PSBT that contains the pending channel output. If a base PSBT was
+    provided in the PsbtShim, this is the base PSBT with one additional output.
+    If no base PSBT was specified, this is an otherwise empty PSBT with exactly
+    one output.
+    */
+    bytes psbt = 3;
+}
+
+message BatchOpenChannelRequest {
+    // The list of channels to open.
+    repeated BatchOpenChannel channels = 1;
+
+    // The target number of blocks that the funding transaction should be
+    // confirmed by.
+    int32 target_conf = 2;
+
+    // A manual fee rate set in sat/vByte that should be used when crafting the
+    // funding transaction.
+    int64 sat_per_vbyte = 3;
+
+    // The minimum number of confirmations each one of your outputs used for
+    // the funding transaction must satisfy.
+    int32 min_confs = 4;
+
+    // Whether unconfirmed outputs should be used as inputs for the funding
+    // transaction.
+    bool spend_unconfirmed = 5;
+
+    // An optional label for the batch transaction, limited to 500 characters.
+    string label = 6;
+
+    // The strategy to use for selecting coins during batch opening channels.
+    CoinSelectionStrategy coin_selection_strategy = 7;
+}
+
+message BatchOpenChannel {
+    // The pubkey of the node to open a channel with. When using REST, this
+    // field must be encoded as base64.
+    bytes node_pubkey = 1;
+
+    // The number of satoshis the wallet should commit to the channel.
+    int64 local_funding_amount = 2;
+
+    // The number of satoshis to push to the remote side as part of the initial
+    // commitment state.
+    int64 push_sat = 3;
+
+    // Whether this channel should be private, not announced to the greater
+    // network.
+    bool private = 4;
+
+    // The minimum value in millisatoshi we will require for incoming HTLCs on
+    // the channel.
+    int64 min_htlc_msat = 5;
+
+    // The delay we require on the remote's commitment transaction. If this is
+    // not set, it will be scaled automatically with the channel size.
+    uint32 remote_csv_delay = 6;
+
+    /*
+    Close address is an optional address which specifies the address to which
+    funds should be paid out to upon cooperative close. This field may only be
+    set if the peer supports the option upfront feature bit (call listpeers
+    to check). The remote peer will only accept cooperative closes to this
+    address if it is set.
+
+    Note: If this value is set on channel creation, you will *not* be able to
+    cooperatively close out to a different address.
+    */
+    string close_address = 7;
+
+    /*
+    An optional, unique identifier of 32 random bytes that will be used as the
+    pending channel ID to identify the channel while it is in the pre-pending
+    state.
+    */
+    bytes pending_chan_id = 8;
+
+    /*
+    The explicit commitment type to use. Note this field will only be used if
+    the remote peer supports explicit channel negotiation.
+    */
+    CommitmentType commitment_type = 9;
+
+    /*
+    The maximum amount of coins in millisatoshi that can be pending within
+    the channel. It only applies to the remote party.
+    */
+    uint64 remote_max_value_in_flight_msat = 10;
+
+    /*
+    The maximum number of concurrent HTLCs we will allow the remote party to add
+    to the commitment transaction.
+    */
+    uint32 remote_max_htlcs = 11;
+
+    /*
+    Max local csv is the maximum csv delay we will allow for our own commitment
+    transaction.
+    */
+    uint32 max_local_csv = 12;
+
+    /*
+    If this is true, then a zero-conf channel open will be attempted.
+    */
+    bool zero_conf = 13;
+
+    /*
+    If this is true, then an option-scid-alias channel-type open will be
+    attempted.
+    */
+    bool scid_alias = 14;
+
+    /*
+    The base fee charged regardless of the number of milli-satoshis sent.
+    */
+    uint64 base_fee = 15;
+
+    /*
+    The fee rate in ppm (parts per million) that will be charged in
+    proportion of the value of each forwarded HTLC.
+    */
+    uint64 fee_rate = 16;
+
+    /*
+    If use_base_fee is true the open channel announcement will update the
+    channel base fee with the value specified in base_fee. In the case of
+    a base_fee of 0 use_base_fee is needed downstream to distinguish whether
+    to use the default base fee value specified in the config or 0.
+    */
+    bool use_base_fee = 17;
+
+    /*
+    If use_fee_rate is true the open channel announcement will update the
+    channel fee rate with the value specified in fee_rate. In the case of
+    a fee_rate of 0 use_fee_rate is needed downstream to distinguish whether
+    to use the default fee rate value specified in the config or 0.
+    */
+    bool use_fee_rate = 18;
+
+    /*
+    The number of satoshis we require the remote peer to reserve. This value,
+    if specified, must be above the dust limit and below 20% of the channel
+    capacity.
+    */
+    uint64 remote_chan_reserve_sat = 19;
+
+    /*
+    An optional note-to-self to go along with the channel containing some
+    useful information. This is only ever stored locally and in no way impacts
+    the channel's operation.
+    */
+    string memo = 20;
+}
+
+message BatchOpenChannelResponse {
+    repeated PendingUpdate pending_channels = 1;
+}
+
+message OpenChannelRequest {
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // funding transaction.
+    uint64 sat_per_vbyte = 1;
+
+    /*
+    The pubkey of the node to open a channel with. When using REST, this field
+    must be encoded as base64.
+    */
+    bytes node_pubkey = 2;
+
+    /*
+    The hex encoded pubkey of the node to open a channel with. Deprecated now
+    that the REST gateway supports base64 encoding of bytes fields.
+    */
+    string node_pubkey_string = 3 [deprecated = true];
+
+    // The number of satoshis the wallet should commit to the channel
+    int64 local_funding_amount = 4;
+
+    // The number of satoshis to push to the remote side as part of the initial
+    // commitment state
+    int64 push_sat = 5;
+
+    // The target number of blocks that the funding transaction should be
+    // confirmed by.
+    int32 target_conf = 6;
+
+    // Deprecated, use sat_per_vbyte.
+    // A manual fee rate set in sat/vbyte that should be used when crafting the
+    // funding transaction.
+    int64 sat_per_byte = 7 [deprecated = true];
+
+    // Whether this channel should be private, not announced to the greater
+    // network.
+    bool private = 8;
+
+    // The minimum value in millisatoshi we will require for incoming HTLCs on
+    // the channel.
+    int64 min_htlc_msat = 9;
+
+    // The delay we require on the remote's commitment transaction. If this is
+    // not set, it will be scaled automatically with the channel size.
+    uint32 remote_csv_delay = 10;
+
+    // The minimum number of confirmations each one of your outputs used for
+    // the funding transaction must satisfy.
+    int32 min_confs = 11;
+
+    // Whether unconfirmed outputs should be used as inputs for the funding
+    // transaction.
+    bool spend_unconfirmed = 12;
+
+    /*
+    Close address is an optional address which specifies the address to which
+    funds should be paid out to upon cooperative close. This field may only be
+    set if the peer supports the option upfront feature bit (call listpeers
+    to check). The remote peer will only accept cooperative closes to this
+    address if it is set.
+
+    Note: If this value is set on channel creation, you will *not* be able to
+    cooperatively close out to a different address.
+    */
+    string close_address = 13;
+
+    /*
+    Funding shims are an optional argument that allow the caller to intercept
+    certain funding functionality. For example, a shim can be provided to use a
+    particular key for the commitment key (ideally cold) rather than use one
+    that is generated by the wallet as normal, or signal that signing will be
+    carried out in an interactive manner (PSBT based).
+    */
+    FundingShim funding_shim = 14;
+
+    /*
+    The maximum amount of coins in millisatoshi that can be pending within
+    the channel. It only applies to the remote party.
+    */
+    uint64 remote_max_value_in_flight_msat = 15;
+
+    /*
+    The maximum number of concurrent HTLCs we will allow the remote party to add
+    to the commitment transaction.
+    */
+    uint32 remote_max_htlcs = 16;
+
+    /*
+    Max local csv is the maximum csv delay we will allow for our own commitment
+    transaction.
+    */
+    uint32 max_local_csv = 17;
+
+    /*
+    The explicit commitment type to use. Note this field will only be used if
+    the remote peer supports explicit channel negotiation.
+    */
+    CommitmentType commitment_type = 18;
+
+    /*
+    If this is true, then a zero-conf channel open will be attempted.
+    */
+    bool zero_conf = 19;
+
+    /*
+    If this is true, then an option-scid-alias channel-type open will be
+    attempted.
+    */
+    bool scid_alias = 20;
+
+    /*
+    The base fee charged regardless of the number of milli-satoshis sent.
+    */
+    uint64 base_fee = 21;
+
+    /*
+    The fee rate in ppm (parts per million) that will be charged in
+    proportion of the value of each forwarded HTLC.
+    */
+    uint64 fee_rate = 22;
+
+    /*
+    If use_base_fee is true the open channel announcement will update the
+    channel base fee with the value specified in base_fee. In the case of
+    a base_fee of 0 use_base_fee is needed downstream to distinguish whether
+    to use the default base fee value specified in the config or 0.
+    */
+    bool use_base_fee = 23;
+
+    /*
+    If use_fee_rate is true the open channel announcement will update the
+    channel fee rate with the value specified in fee_rate. In the case of
+    a fee_rate of 0 use_fee_rate is needed downstream to distinguish whether
+    to use the default fee rate value specified in the config or 0.
+    */
+    bool use_fee_rate = 24;
+
+    /*
+    The number of satoshis we require the remote peer to reserve. This value,
+    if specified, must be above the dust limit and below 20% of the channel
+    capacity.
+    */
+    uint64 remote_chan_reserve_sat = 25;
+
+    /*
+    If set, then lnd will attempt to commit all the coins under control of the
+    internal wallet to open the channel, and the LocalFundingAmount field must
+    be zero and is ignored.
+    */
+    bool fund_max = 26;
+
+    /*
+    An optional note-to-self to go along with the channel containing some
+    useful information. This is only ever stored locally and in no way impacts
+    the channel's operation.
+    */
+    string memo = 27;
+
+    /*
+    A list of selected outpoints that are allocated for channel funding.
+    */
+    repeated OutPoint outpoints = 28;
+}
+message OpenStatusUpdate {
+    oneof update {
+        /*
+        Signals that the channel is now fully negotiated and the funding
+        transaction published.
+        */
+        PendingUpdate chan_pending = 1;
+
+        /*
+        Signals that the channel's funding transaction has now reached the
+        required number of confirmations on chain and can be used.
+        */
+        ChannelOpenUpdate chan_open = 3;
+
+        /*
+        Signals that the funding process has been suspended and the construction
+        of a PSBT that funds the channel PK script is now required.
+        */
+        ReadyForPsbtFunding psbt_fund = 5;
+    }
+
+    /*
+    The pending channel ID of the created channel. This value may be used to
+    further the funding flow manually via the FundingStateStep method.
+    */
+    bytes pending_chan_id = 4;
+}
+
+message KeyLocator {
+    // The family of key being identified.
+    int32 key_family = 1;
+
+    // The precise index of the key being identified.
+    int32 key_index = 2;
+}
+
+message KeyDescriptor {
+    /*
+    The raw bytes of the key being identified.
+    */
+    bytes raw_key_bytes = 1;
+
+    /*
+    The key locator that identifies which key to use for signing.
+    */
+    KeyLocator key_loc = 2;
+}
+
+message ChanPointShim {
+    /*
+    The size of the pre-crafted output to be used as the channel point for this
+    channel funding.
+    */
+    int64 amt = 1;
+
+    // The target channel point to reference in created commitment transactions.
+    ChannelPoint chan_point = 2;
+
+    // Our local key to use when creating the multi-sig output.
+    KeyDescriptor local_key = 3;
+
+    // The key of the remote party to use when creating the multi-sig output.
+    bytes remote_key = 4;
+
+    /*
+    If non-zero, then this will be used as the pending channel ID on the wire
+    protocol to initiate the funding request. This is an optional field, and
+    should only be set if the responder is already expecting a specific pending
+    channel ID.
+    */
+    bytes pending_chan_id = 5;
+
+    /*
+    This uint32 indicates if this channel is to be considered 'frozen'. A frozen
+    channel does not allow a cooperative channel close by the initiator. The
+    thaw_height is the height that this restriction stops applying to the
+    channel. The height can be interpreted in two ways: as a relative height if
+    the value is less than 500,000, or as an absolute height otherwise.
+    */
+    uint32 thaw_height = 6;
+
+    /*
+    Indicates that the funding output is using a MuSig2 multi-sig output.
+    */
+    bool musig2 = 7;
+}
+
+message PsbtShim {
+    /*
+    A unique identifier of 32 random bytes that will be used as the pending
+    channel ID to identify the PSBT state machine when interacting with it and
+    on the wire protocol to initiate the funding request.
+    */
+    bytes pending_chan_id = 1;
+
+    /*
+    An optional base PSBT the new channel output will be added to. If this is
+    non-empty, it must be a binary serialized PSBT.
+    */
+    bytes base_psbt = 2;
+
+    /*
+    If a channel should be part of a batch (multiple channel openings in one
+    transaction), it can be dangerous if the whole batch transaction is
+    published too early before all channel opening negotiations are completed.
+    This flag prevents this particular channel from broadcasting the transaction
+    after the negotiation with the remote peer. In a batch of channel openings
+    this flag should be set to true for every channel but the very last.
+    */
+    bool no_publish = 3;
+}
+
+message FundingShim {
+    oneof shim {
+        /*
+        A channel shim where the channel point was fully constructed outside
+        of lnd's wallet and the transaction might already be published.
+        */
+        ChanPointShim chan_point_shim = 1;
+
+        /*
+        A channel shim that uses a PSBT to fund and sign the channel funding
+        transaction.
+        */
+        PsbtShim psbt_shim = 2;
+    }
+}
+
+message FundingShimCancel {
+    // The pending channel ID of the channel to cancel the funding shim for.
+    bytes pending_chan_id = 1;
+}
+
+message FundingPsbtVerify {
+    /*
+    The funded but not yet signed PSBT that sends the exact channel capacity
+    amount to the PK script returned in the open channel message in a previous
+    step.
+    */
+    bytes funded_psbt = 1;
+
+    // The pending channel ID of the channel to get the PSBT for.
+    bytes pending_chan_id = 2;
+
+    /*
+    Can only be used if the no_publish flag was set to true in the OpenChannel
+    call meaning that the caller is solely responsible for publishing the final
+    funding transaction. If skip_finalize is set to true then lnd will not wait
+    for a FundingPsbtFinalize state step and instead assumes that a transaction
+    with the same TXID as the passed in PSBT will eventually confirm.
+    IT IS ABSOLUTELY IMPERATIVE that the TXID of the transaction that is
+    eventually published does have the _same TXID_ as the verified PSBT. That
+    means no inputs or outputs can change, only signatures can be added. If the
+    TXID changes between this call and the publish step then the channel will
+    never be created and the funds will be in limbo.
+    */
+    bool skip_finalize = 3;
+}
+
+message FundingPsbtFinalize {
+    /*
+    The funded PSBT that contains all witness data to send the exact channel
+    capacity amount to the PK script returned in the open channel message in a
+    previous step. Cannot be set at the same time as final_raw_tx.
+    */
+    bytes signed_psbt = 1;
+
+    // The pending channel ID of the channel to get the PSBT for.
+    bytes pending_chan_id = 2;
+
+    /*
+    As an alternative to the signed PSBT with all witness data, the final raw
+    wire format transaction can also be specified directly. Cannot be set at the
+    same time as signed_psbt.
+    */
+    bytes final_raw_tx = 3;
+}
+
+message FundingTransitionMsg {
+    oneof trigger {
+        /*
+        The funding shim to register. This should be used before any
+        channel funding has began by the remote party, as it is intended as a
+        preparatory step for the full channel funding.
+        */
+        FundingShim shim_register = 1;
+
+        // Used to cancel an existing registered funding shim.
+        FundingShimCancel shim_cancel = 2;
+
+        /*
+        Used to continue a funding flow that was initiated to be executed
+        through a PSBT. This step verifies that the PSBT contains the correct
+        outputs to fund the channel.
+        */
+        FundingPsbtVerify psbt_verify = 3;
+
+        /*
+        Used to continue a funding flow that was initiated to be executed
+        through a PSBT. This step finalizes the funded and signed PSBT, finishes
+        negotiation with the peer and finally publishes the resulting funding
+        transaction.
+        */
+        FundingPsbtFinalize psbt_finalize = 4;
+    }
+}
+
+message FundingStateStepResp {
+}
+
+message PendingHTLC {
+    // The direction within the channel that the htlc was sent
+    bool incoming = 1;
+
+    // The total value of the htlc
+    int64 amount = 2;
+
+    // The final output to be swept back to the user's wallet
+    string outpoint = 3;
+
+    // The next block height at which we can spend the current stage
+    uint32 maturity_height = 4;
+
+    /*
+       The number of blocks remaining until the current stage can be swept.
+       Negative values indicate how many blocks have passed since becoming
+       mature.
+    */
+    int32 blocks_til_maturity = 5;
+
+    // Indicates whether the htlc is in its first or second stage of recovery
+    uint32 stage = 6;
+}
+
+message PendingChannelsRequest {
+    // Indicates whether to include the raw transaction hex for
+    // waiting_close_channels.
+    bool include_raw_tx = 1;
+}
+message PendingChannelsResponse {
+    message PendingChannel {
+        string remote_node_pub = 1;
+        string channel_point = 2;
+
+        int64 capacity = 3;
+
+        int64 local_balance = 4;
+        int64 remote_balance = 5;
+
+        // The minimum satoshis this node is required to reserve in its
+        // balance.
+        int64 local_chan_reserve_sat = 6;
+
+        /*
+        The minimum satoshis the other node is required to reserve in its
+        balance.
+        */
+        int64 remote_chan_reserve_sat = 7;
+
+        // The party that initiated opening the channel.
+        Initiator initiator = 8;
+
+        // The commitment type used by this channel.
+        CommitmentType commitment_type = 9;
+
+        // Total number of forwarding packages created in this channel.
+        int64 num_forwarding_packages = 10;
+
+        // A set of flags showing the current state of the channel.
+        string chan_status_flags = 11;
+
+        // Whether this channel is advertised to the network or not.
+        bool private = 12;
+
+        /*
+        An optional note-to-self to go along with the channel containing some
+        useful information. This is only ever stored locally and in no way
+        impacts the channel's operation.
+        */
+        string memo = 13;
+    }
+
+    message PendingOpenChannel {
+        // The pending channel
+        PendingChannel channel = 1;
+
+        /*
+        The amount calculated to be paid in fees for the current set of
+        commitment transactions. The fee amount is persisted with the channel
+        in order to allow the fee amount to be removed and recalculated with
+        each channel state update, including updates that happen after a system
+        restart.
+        */
+        int64 commit_fee = 4;
+
+        // The weight of the commitment transaction
+        int64 commit_weight = 5;
+
+        /*
+        The required number of satoshis per kilo-weight that the requester will
+        pay at all times, for both the funding transaction and commitment
+        transaction. This value can later be updated once the channel is open.
+        */
+        int64 fee_per_kw = 6;
+
+        // Previously used for confirmation_height. Do not reuse.
+        reserved 2;
+
+        // The number of blocks until the funding transaction is considered
+        // expired. If this value gets close to zero, there is a risk that the
+        // channel funding will be canceled by the channel responder. The
+        // channel should be fee bumped using CPFP (see walletrpc.BumpFee) to
+        // ensure that the channel confirms in time. Otherwise a force-close
+        // will be necessary if the channel confirms after the funding
+        // transaction expires. A negative value means the channel responder has
+        // very likely canceled the funding and the channel will never become
+        // fully operational.
+        int32 funding_expiry_blocks = 3;
+    }
+
+    message WaitingCloseChannel {
+        // The pending channel waiting for closing tx to confirm
+        PendingChannel channel = 1;
+
+        // The balance in satoshis encumbered in this channel
+        int64 limbo_balance = 2;
+
+        /*
+        A list of valid commitment transactions. Any of these can confirm at
+        this point.
+        */
+        Commitments commitments = 3;
+
+        // The transaction id of the closing transaction
+        string closing_txid = 4;
+
+        // The raw hex encoded bytes of the closing transaction. Included if
+        // include_raw_tx in the request is true.
+        string closing_tx_hex = 5;
+    }
+
+    message Commitments {
+        // Hash of the local version of the commitment tx.
+        string local_txid = 1;
+
+        // Hash of the remote version of the commitment tx.
+        string remote_txid = 2;
+
+        // Hash of the remote pending version of the commitment tx.
+        string remote_pending_txid = 3;
+
+        /*
+        The amount in satoshis calculated to be paid in fees for the local
+        commitment.
+        */
+        uint64 local_commit_fee_sat = 4;
+
+        /*
+        The amount in satoshis calculated to be paid in fees for the remote
+        commitment.
+        */
+        uint64 remote_commit_fee_sat = 5;
+
+        /*
+        The amount in satoshis calculated to be paid in fees for the remote
+        pending commitment.
+        */
+        uint64 remote_pending_commit_fee_sat = 6;
+    }
+
+    message ClosedChannel {
+        // The pending channel to be closed
+        PendingChannel channel = 1;
+
+        // The transaction id of the closing transaction
+        string closing_txid = 2;
+    }
+
+    message ForceClosedChannel {
+        // The pending channel to be force closed
+        PendingChannel channel = 1;
+
+        // The transaction id of the closing transaction
+        string closing_txid = 2;
+
+        // The balance in satoshis encumbered in this pending channel
+        int64 limbo_balance = 3;
+
+        // The height at which funds can be swept into the wallet
+        uint32 maturity_height = 4;
+
+        /*
+          Remaining # of blocks until the commitment output can be swept.
+          Negative values indicate how many blocks have passed since becoming
+          mature.
+        */
+        int32 blocks_til_maturity = 5;
+
+        // The total value of funds successfully recovered from this channel
+        int64 recovered_balance = 6;
+
+        repeated PendingHTLC pending_htlcs = 8;
+
+        /*
+          There are three resolution states for the anchor:
+          limbo, lost and recovered. Derive the current state
+          from the limbo and recovered balances.
+        */
+        enum AnchorState {
+            // The recovered_balance is zero and limbo_balance is non-zero.
+            LIMBO = 0;
+            // The recovered_balance is non-zero.
+            RECOVERED = 1;
+            // A state that is neither LIMBO nor RECOVERED.
+            LOST = 2;
+        }
+
+        AnchorState anchor = 9;
+    }
+
+    // The balance in satoshis encumbered in pending channels
+    int64 total_limbo_balance = 1;
+
+    // Channels pending opening
+    repeated PendingOpenChannel pending_open_channels = 2;
+
+    /*
+    Deprecated: Channels pending closing previously contained cooperatively
+    closed channels with a single confirmation. These channels are now
+    considered closed from the time we see them on chain.
+    */
+    repeated ClosedChannel pending_closing_channels = 3 [deprecated = true];
+
+    // Channels pending force closing
+    repeated ForceClosedChannel pending_force_closing_channels = 4;
+
+    // Channels waiting for closing tx to confirm
+    repeated WaitingCloseChannel waiting_close_channels = 5;
+}
+
+message ChannelEventSubscription {
+}
+
+message ChannelEventUpdate {
+    oneof channel {
+        Channel open_channel = 1;
+        ChannelCloseSummary closed_channel = 2;
+        ChannelPoint active_channel = 3;
+        ChannelPoint inactive_channel = 4;
+        PendingUpdate pending_open_channel = 6;
+        ChannelPoint fully_resolved_channel = 7;
+    }
+
+    enum UpdateType {
+        OPEN_CHANNEL = 0;
+        CLOSED_CHANNEL = 1;
+        ACTIVE_CHANNEL = 2;
+        INACTIVE_CHANNEL = 3;
+        PENDING_OPEN_CHANNEL = 4;
+        FULLY_RESOLVED_CHANNEL = 5;
+    }
+
+    UpdateType type = 5;
+}
+
+message WalletAccountBalance {
+    // The confirmed balance of the account (with >= 1 confirmations).
+    int64 confirmed_balance = 1;
+
+    // The unconfirmed balance of the account (with 0 confirmations).
+    int64 unconfirmed_balance = 2;
+}
+
+message WalletBalanceRequest {
+    // The wallet account the balance is shown for.
+    // If this is not specified, the balance of the "default" account is shown.
+    string account = 1;
+
+    // The minimum number of confirmations each one of your outputs used for the
+    // funding transaction must satisfy. If this is not specified, the default
+    // value of 1 is used.
+    int32 min_confs = 2;
+}
+
+message WalletBalanceResponse {
+    // The balance of the wallet
+    int64 total_balance = 1;
+
+    // The confirmed balance of a wallet(with >= 1 confirmations)
+    int64 confirmed_balance = 2;
+
+    // The unconfirmed balance of a wallet(with 0 confirmations)
+    int64 unconfirmed_balance = 3;
+
+    // The total amount of wallet UTXOs held in outputs that are locked for
+    // other usage.
+    int64 locked_balance = 5;
+
+    // The amount of reserve required.
+    int64 reserved_balance_anchor_chan = 6;
+
+    // A mapping of each wallet account's name to its balance.
+    map<string, WalletAccountBalance> account_balance = 4;
+}
+
+message Amount {
+    // Value denominated in satoshis.
+    uint64 sat = 1;
+
+    // Value denominated in milli-satoshis.
+    uint64 msat = 2;
+}
+
+message ChannelBalanceRequest {
+}
+message ChannelBalanceResponse {
+    // Deprecated. Sum of channels balances denominated in satoshis
+    int64 balance = 1 [deprecated = true];
+
+    // Deprecated. Sum of channels pending balances denominated in satoshis
+    int64 pending_open_balance = 2 [deprecated = true];
+
+    // Sum of channels local balances.
+    Amount local_balance = 3;
+
+    // Sum of channels remote balances.
+    Amount remote_balance = 4;
+
+    // Sum of channels local unsettled balances.
+    Amount unsettled_local_balance = 5;
+
+    // Sum of channels remote unsettled balances.
+    Amount unsettled_remote_balance = 6;
+
+    // Sum of channels pending local balances.
+    Amount pending_open_local_balance = 7;
+
+    // Sum of channels pending remote balances.
+    Amount pending_open_remote_balance = 8;
+}
+
+message QueryRoutesRequest {
+    // The 33-byte hex-encoded public key for the payment destination
+    string pub_key = 1;
+
+    /*
+    The amount to send expressed in satoshis.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt = 2;
+
+    /*
+    The amount to send expressed in millisatoshis.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt_msat = 12;
+
+    reserved 3;
+
+    /*
+    An optional CLTV delta from the current height that should be used for the
+    timelock of the final hop. Note that unlike SendPayment, QueryRoutes does
+    not add any additional block padding on top of final_ctlv_delta. This
+    padding of a few blocks needs to be added manually or otherwise failures may
+    happen when a block comes in while the payment is in flight.
+
+    Note: must not be set if making a payment to a blinded path (delta is
+    set by the aggregate parameters provided by blinded_payment_paths)
+    */
+    int32 final_cltv_delta = 4;
+
+    /*
+    The maximum number of satoshis that will be paid as a fee of the payment.
+    This value can be represented either as a percentage of the amount being
+    sent, or as a fixed amount of the maximum fee the user is willing the pay to
+    send the payment. If not specified, lnd will use a default value of 100%
+    fees for small amounts (<=1k sat) or 5% fees for larger amounts.
+    */
+    FeeLimit fee_limit = 5;
+
+    /*
+    A list of nodes to ignore during path finding. When using REST, these fields
+    must be encoded as base64.
+    */
+    repeated bytes ignored_nodes = 6;
+
+    /*
+    Deprecated. A list of edges to ignore during path finding.
+    */
+    repeated EdgeLocator ignored_edges = 7 [deprecated = true];
+
+    /*
+    The source node where the request route should originated from. If empty,
+    self is assumed.
+    */
+    string source_pub_key = 8;
+
+    /*
+    If set to true, edge probabilities from mission control will be used to get
+    the optimal route.
+    */
+    bool use_mission_control = 9;
+
+    /*
+    A list of directed node pairs that will be ignored during path finding.
+    */
+    repeated NodePair ignored_pairs = 10;
+
+    /*
+    An optional maximum total time lock for the route. If the source is empty or
+    ourselves, this should not exceed lnd's `--max-cltv-expiry` setting. If
+    zero, then the value of `--max-cltv-expiry` is used as the limit.
+    */
+    uint32 cltv_limit = 11;
+
+    /*
+    An optional field that can be used to pass an arbitrary set of TLV records
+    to a peer which understands the new records. This can be used to pass
+    application specific data during the payment attempt. If the destination
+    does not support the specified records, an error will be returned.
+    Record types are required to be in the custom range >= 65536. When using
+    REST, the values must be encoded as base64.
+    */
+    map<uint64, bytes> dest_custom_records = 13;
+
+    /*
+    The channel id of the channel that must be taken to the first hop. If zero,
+    any channel may be used.
+    */
+    uint64 outgoing_chan_id = 14 [jstype = JS_STRING];
+
+    /*
+    The pubkey of the last hop of the route. If empty, any hop may be used.
+    */
+    bytes last_hop_pubkey = 15;
+
+    /*
+    Optional route hints to reach the destination through private channels.
+    */
+    repeated lnrpc.RouteHint route_hints = 16;
+
+    /*
+    An optional blinded path(s) to reach the destination. Note that the
+    introduction node must be provided as the first hop in the route.
+    */
+    repeated BlindedPaymentPath blinded_payment_paths = 19;
+
+    /*
+    Features assumed to be supported by the final node. All transitive feature
+    dependencies must also be set properly. For a given feature bit pair, either
+    optional or remote may be set, but not both. If this field is nil or empty,
+    the router will try to load destination features from the graph as a
+    fallback.
+
+    Note: must not be set if making a payment to a blinded route (features
+    are provided in blinded_payment_paths).
+    */
+    repeated lnrpc.FeatureBit dest_features = 17;
+
+    /*
+    The time preference for this payment. Set to -1 to optimize for fees
+    only, to 1 to optimize for reliability only or a value inbetween for a mix.
+    */
+    double time_pref = 18;
+}
+
+message NodePair {
+    /*
+    The sending node of the pair. When using REST, this field must be encoded as
+    base64.
+    */
+    bytes from = 1;
+
+    /*
+    The receiving node of the pair. When using REST, this field must be encoded
+    as base64.
+    */
+    bytes to = 2;
+}
+
+message EdgeLocator {
+    // The short channel id of this edge.
+    uint64 channel_id = 1 [jstype = JS_STRING];
+
+    /*
+    The direction of this edge. If direction_reverse is false, the direction
+    of this edge is from the channel endpoint with the lexicographically smaller
+    pub key to the endpoint with the larger pub key. If direction_reverse is
+    is true, the edge goes the other way.
+    */
+    bool direction_reverse = 2;
+}
+
+message QueryRoutesResponse {
+    /*
+    The route that results from the path finding operation. This is still a
+    repeated field to retain backwards compatibility.
+    */
+    repeated Route routes = 1;
+
+    /*
+    The success probability of the returned route based on the current mission
+    control state. [EXPERIMENTAL]
+    */
+    double success_prob = 2;
+}
+
+message Hop {
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 chan_id = 1 [jstype = JS_STRING];
+    int64 chan_capacity = 2 [deprecated = true];
+    int64 amt_to_forward = 3 [deprecated = true];
+    int64 fee = 4 [deprecated = true];
+    uint32 expiry = 5;
+    int64 amt_to_forward_msat = 6;
+    int64 fee_msat = 7;
+
+    /*
+    An optional public key of the hop. If the public key is given, the payment
+    can be executed without relying on a copy of the channel graph.
+    */
+    string pub_key = 8;
+
+    /*
+    If set to true, then this hop will be encoded using the new variable length
+    TLV format. Note that if any custom tlv_records below are specified, then
+    this field MUST be set to true for them to be encoded properly.
+    */
+    bool tlv_payload = 9 [deprecated = true];
+
+    /*
+    An optional TLV record that signals the use of an MPP payment. If present,
+    the receiver will enforce that the same mpp_record is included in the final
+    hop payload of all non-zero payments in the HTLC set. If empty, a regular
+    single-shot payment is or was attempted.
+    */
+    MPPRecord mpp_record = 10;
+
+    /*
+    An optional TLV record that signals the use of an AMP payment. If present,
+    the receiver will treat all received payments including the same
+    (payment_addr, set_id) pair  as being part of one logical payment. The
+    payment will be settled by XORing the root_share's together and deriving the
+    child hashes and preimages according to BOLT XX. Must be used in conjunction
+    with mpp_record.
+    */
+    AMPRecord amp_record = 12;
+
+    /*
+    An optional set of key-value TLV records. This is useful within the context
+    of the SendToRoute call as it allows callers to specify arbitrary K-V pairs
+    to drop off at each hop within the onion.
+    */
+    map<uint64, bytes> custom_records = 11;
+
+    // The payment metadata to send along with the payment to the payee.
+    bytes metadata = 13;
+
+    /*
+    Blinding point is an optional blinding point included for introduction
+    nodes in blinded paths. This field is mandatory for hops that represents
+    the introduction point in a blinded path.
+    */
+    bytes blinding_point = 14;
+
+    /*
+    Encrypted data is a receiver-produced blob of data that provides hops
+    in a blinded route with forwarding data. As this data is encrypted by
+    the recipient, we will not be able to parse it - it is essentially an
+    arbitrary blob of data from our node's perspective. This field is
+    mandatory for all hops in a blinded path, including the introduction
+    node.
+    */
+    bytes encrypted_data = 15;
+
+    /*
+    The total amount that is sent to the recipient (possibly across multiple
+    HTLCs), as specified by the sender when making a payment to a blinded path.
+    This value is only set in the final hop payload of a blinded payment. This
+    value is analogous to the MPPRecord that is used for regular (non-blinded)
+    MPP payments.
+    */
+    uint64 total_amt_msat = 16;
+}
+
+message MPPRecord {
+    /*
+    A unique, random identifier used to authenticate the sender as the intended
+    payer of a multi-path payment. The payment_addr must be the same for all
+    subpayments, and match the payment_addr provided in the receiver's invoice.
+    The same payment_addr must be used on all subpayments. This is also called
+    payment secret in specifications (e.g. BOLT 11).
+    */
+    bytes payment_addr = 11;
+
+    /*
+    The total amount in milli-satoshis being sent as part of a larger multi-path
+    payment. The caller is responsible for ensuring subpayments to the same node
+    and payment_hash sum exactly to total_amt_msat. The same
+    total_amt_msat must be used on all subpayments.
+    */
+    int64 total_amt_msat = 10;
+}
+
+message AMPRecord {
+    bytes root_share = 1;
+
+    bytes set_id = 2;
+
+    uint32 child_index = 3;
+}
+
+/*
+A path through the channel graph which runs over one or more channels in
+succession. This struct carries all the information required to craft the
+Sphinx onion packet, and send the payment along the first hop in the path. A
+route is only selected as valid if all the channels have sufficient capacity to
+carry the initial payment amount after fees are accounted for.
+*/
+message Route {
+    /*
+    The cumulative (final) time lock across the entire route. This is the CLTV
+    value that should be extended to the first hop in the route. All other hops
+    will decrement the time-lock as advertised, leaving enough time for all
+    hops to wait for or present the payment preimage to complete the payment.
+    */
+    uint32 total_time_lock = 1;
+
+    /*
+    The sum of the fees paid at each hop within the final route. In the case
+    of a one-hop payment, this value will be zero as we don't need to pay a fee
+    to ourselves.
+    */
+    int64 total_fees = 2 [deprecated = true];
+
+    /*
+    The total amount of funds required to complete a payment over this route.
+    This value includes the cumulative fees at each hop. As a result, the HTLC
+    extended to the first-hop in the route will need to have at least this many
+    satoshis, otherwise the route will fail at an intermediate node due to an
+    insufficient amount of fees.
+    */
+    int64 total_amt = 3 [deprecated = true];
+
+    /*
+    Contains details concerning the specific forwarding details at each hop.
+    */
+    repeated Hop hops = 4;
+
+    /*
+    The total fees in millisatoshis.
+    */
+    int64 total_fees_msat = 5;
+
+    /*
+    The total amount in millisatoshis.
+    */
+    int64 total_amt_msat = 6;
+}
+
+message NodeInfoRequest {
+    // The 33-byte hex-encoded compressed public of the target node
+    string pub_key = 1;
+
+    // If true, will include all known channels associated with the node.
+    bool include_channels = 2;
+}
+
+message NodeInfo {
+    /*
+    An individual vertex/node within the channel graph. A node is
+    connected to other nodes by one or more channel edges emanating from it. As
+    the graph is directed, a node will also have an incoming edge attached to
+    it for each outgoing edge.
+    */
+    LightningNode node = 1;
+
+    // The total number of channels for the node.
+    uint32 num_channels = 2;
+
+    // The sum of all channels capacity for the node, denominated in satoshis.
+    int64 total_capacity = 3;
+
+    // A list of all public channels for the node.
+    repeated ChannelEdge channels = 4;
+}
+
+/*
+An individual vertex/node within the channel graph. A node is
+connected to other nodes by one or more channel edges emanating from it. As the
+graph is directed, a node will also have an incoming edge attached to it for
+each outgoing edge.
+*/
+message LightningNode {
+    uint32 last_update = 1;
+    string pub_key = 2;
+    string alias = 3;
+    repeated NodeAddress addresses = 4;
+    string color = 5;
+    map<uint32, Feature> features = 6;
+
+    // Custom node announcement tlv records.
+    map<uint64, bytes> custom_records = 7;
+}
+
+message NodeAddress {
+    string network = 1;
+    string addr = 2;
+}
+
+message RoutingPolicy {
+    uint32 time_lock_delta = 1;
+    int64 min_htlc = 2;
+    int64 fee_base_msat = 3;
+    int64 fee_rate_milli_msat = 4;
+    bool disabled = 5;
+    uint64 max_htlc_msat = 6;
+    uint32 last_update = 7;
+
+    // Custom channel update tlv records.
+    map<uint64, bytes> custom_records = 8;
+
+    int32 inbound_fee_base_msat = 9;
+    int32 inbound_fee_rate_milli_msat = 10;
+}
+
+/*
+A fully authenticated channel along with all its unique attributes.
+Once an authenticated channel announcement has been processed on the network,
+then an instance of ChannelEdgeInfo encapsulating the channels attributes is
+stored. The other portions relevant to routing policy of a channel are stored
+within a ChannelEdgePolicy for each direction of the channel.
+*/
+message ChannelEdge {
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 channel_id = 1 [jstype = JS_STRING];
+    string chan_point = 2;
+
+    uint32 last_update = 3 [deprecated = true];
+
+    string node1_pub = 4;
+    string node2_pub = 5;
+
+    int64 capacity = 6;
+
+    RoutingPolicy node1_policy = 7;
+    RoutingPolicy node2_policy = 8;
+
+    // Custom channel announcement tlv records.
+    map<uint64, bytes> custom_records = 9;
+}
+
+message ChannelGraphRequest {
+    /*
+    Whether unannounced channels are included in the response or not. If set,
+    unannounced channels are included. Unannounced channels are both private
+    channels, and public channels that are not yet announced to the network.
+    */
+    bool include_unannounced = 1;
+}
+
+// Returns a new instance of the directed channel graph.
+message ChannelGraph {
+    // The list of `LightningNode`s in this channel graph
+    repeated LightningNode nodes = 1;
+
+    // The list of `ChannelEdge`s in this channel graph
+    repeated ChannelEdge edges = 2;
+}
+
+enum NodeMetricType {
+    UNKNOWN = 0;
+    BETWEENNESS_CENTRALITY = 1;
+}
+
+message NodeMetricsRequest {
+    // The requested node metrics.
+    repeated NodeMetricType types = 1;
+}
+
+message NodeMetricsResponse {
+    /*
+    Betweenness centrality is the sum of the ratio of shortest paths that pass
+    through the node for each pair of nodes in the graph (not counting paths
+    starting or ending at this node).
+    Map of node pubkey to betweenness centrality of the node. Normalized
+    values are in the [0,1] closed interval.
+    */
+    map<string, FloatMetric> betweenness_centrality = 1;
+}
+
+message FloatMetric {
+    // Arbitrary float value.
+    double value = 1;
+
+    // The value normalized to [0,1] or [-1,1].
+    double normalized_value = 2;
+}
+
+message ChanInfoRequest {
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 chan_id = 1 [jstype = JS_STRING];
+
+    // The channel point of the channel in format funding_txid:output_index. If
+    // chan_id is specified, this field is ignored.
+    string chan_point = 2;
+}
+
+message NetworkInfoRequest {
+}
+message NetworkInfo {
+    uint32 graph_diameter = 1;
+    double avg_out_degree = 2;
+    uint32 max_out_degree = 3;
+
+    uint32 num_nodes = 4;
+    uint32 num_channels = 5;
+
+    int64 total_network_capacity = 6;
+
+    double avg_channel_size = 7;
+    int64 min_channel_size = 8;
+    int64 max_channel_size = 9;
+    int64 median_channel_size_sat = 10;
+
+    // The number of edges marked as zombies.
+    uint64 num_zombie_chans = 11;
+
+    // TODO(roasbeef): fee rate info, expiry
+    //  * also additional RPC for tracking fee info once in
+}
+
+message StopRequest {
+}
+message StopResponse {
+}
+
+message GraphTopologySubscription {
+}
+message GraphTopologyUpdate {
+    repeated NodeUpdate node_updates = 1;
+    repeated ChannelEdgeUpdate channel_updates = 2;
+    repeated ClosedChannelUpdate closed_chans = 3;
+}
+message NodeUpdate {
+    /*
+    Deprecated, use node_addresses.
+    */
+    repeated string addresses = 1 [deprecated = true];
+
+    string identity_key = 2;
+
+    /*
+    Deprecated, use features.
+    */
+    bytes global_features = 3 [deprecated = true];
+
+    string alias = 4;
+    string color = 5;
+    repeated NodeAddress node_addresses = 7;
+
+    /*
+    Features that the node has advertised in the init message, node
+    announcements and invoices.
+    */
+    map<uint32, Feature> features = 6;
+}
+message ChannelEdgeUpdate {
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 chan_id = 1 [jstype = JS_STRING];
+
+    ChannelPoint chan_point = 2;
+
+    int64 capacity = 3;
+
+    RoutingPolicy routing_policy = 4;
+
+    string advertising_node = 5;
+    string connecting_node = 6;
+}
+message ClosedChannelUpdate {
+    /*
+    The unique channel ID for the channel. The first 3 bytes are the block
+    height, the next 3 the index within the block, and the last 2 bytes are the
+    output index for the channel.
+    */
+    uint64 chan_id = 1 [jstype = JS_STRING];
+    int64 capacity = 2;
+    uint32 closed_height = 3;
+    ChannelPoint chan_point = 4;
+}
+
+message HopHint {
+    // The public key of the node at the start of the channel.
+    string node_id = 1;
+
+    // The unique identifier of the channel.
+    uint64 chan_id = 2 [jstype = JS_STRING];
+
+    // The base fee of the channel denominated in millisatoshis.
+    uint32 fee_base_msat = 3;
+
+    /*
+    The fee rate of the channel for sending one satoshi across it denominated in
+    millionths of a satoshi.
+    */
+    uint32 fee_proportional_millionths = 4;
+
+    // The time-lock delta of the channel.
+    uint32 cltv_expiry_delta = 5;
+}
+
+message SetID {
+    bytes set_id = 1;
+}
+
+message RouteHint {
+    /*
+    A list of hop hints that when chained together can assist in reaching a
+    specific destination.
+    */
+    repeated HopHint hop_hints = 1;
+}
+
+message BlindedPaymentPath {
+    // The blinded path to send the payment to.
+    BlindedPath blinded_path = 1;
+
+    // The base fee for the blinded path provided, expressed in msat.
+    uint64 base_fee_msat = 2;
+
+    /*
+    The proportional fee for the blinded path provided, expressed in parts
+    per million.
+    */
+    uint32 proportional_fee_rate = 3;
+
+    /*
+    The total CLTV delta for the blinded path provided, including the
+    final CLTV delta for the receiving node.
+    */
+    uint32 total_cltv_delta = 4;
+
+    /*
+    The minimum hltc size that may be sent over the blinded path, expressed
+    in msat.
+    */
+    uint64 htlc_min_msat = 5;
+
+    /*
+    The maximum htlc size that may be sent over the blinded path, expressed
+    in msat.
+    */
+    uint64 htlc_max_msat = 6;
+
+    // The feature bits for the route.
+    repeated FeatureBit features = 7;
+}
+
+message BlindedPath {
+    // The unblinded pubkey of the introduction node for the route.
+    bytes introduction_node = 1;
+
+    // The ephemeral pubkey used by nodes in the blinded route.
+    bytes blinding_point = 2;
+
+    /*
+    A set of blinded node keys and data blobs for the blinded portion of the
+    route. Note that the first hop is expected to be the introduction node,
+    so the route is always expected to have at least one hop.
+    */
+    repeated BlindedHop blinded_hops = 3;
+}
+
+message BlindedHop {
+    // The blinded public key of the node.
+    bytes blinded_node = 1;
+
+    // An encrypted blob of data provided to the blinded node.
+    bytes encrypted_data = 2;
+}
+
+message AMPInvoiceState {
+    // The state the HTLCs associated with this setID are in.
+    InvoiceHTLCState state = 1;
+
+    // The settle index of this HTLC set, if the invoice state is settled.
+    uint64 settle_index = 2;
+
+    // The time this HTLC set was settled expressed in unix epoch.
+    int64 settle_time = 3;
+
+    // The total amount paid for the sub-invoice expressed in milli satoshis.
+    int64 amt_paid_msat = 5;
+}
+
+message Invoice {
+    /*
+    An optional memo to attach along with the invoice. Used for record keeping
+    purposes for the invoice's creator, and will also be set in the description
+    field of the encoded payment request if the description_hash field is not
+    being used.
+    */
+    string memo = 1;
+
+    reserved 2;
+
+    /*
+    The hex-encoded preimage (32 byte) which will allow settling an incoming
+    HTLC payable to this preimage. When using REST, this field must be encoded
+    as base64.
+    */
+    bytes r_preimage = 3;
+
+    /*
+    The hash of the preimage. When using REST, this field must be encoded as
+    base64.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    bytes r_hash = 4;
+
+    /*
+    The value of this invoice in satoshis
+
+    The fields value and value_msat are mutually exclusive.
+    */
+    int64 value = 5;
+
+    /*
+    The value of this invoice in millisatoshis
+
+    The fields value and value_msat are mutually exclusive.
+    */
+    int64 value_msat = 23;
+
+    /*
+    Whether this invoice has been fulfilled.
+
+    The field is deprecated. Use the state field instead (compare to SETTLED).
+    */
+    bool settled = 6 [deprecated = true];
+
+    /*
+    When this invoice was created.
+    Measured in seconds since the unix epoch.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    int64 creation_date = 7;
+
+    /*
+    When this invoice was settled.
+    Measured in seconds since the unix epoch.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    int64 settle_date = 8;
+
+    /*
+    A bare-bones invoice for a payment within the Lightning Network. With the
+    details of the invoice, the sender has all the data necessary to send a
+    payment to the recipient.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    string payment_request = 9;
+
+    /*
+    Hash (SHA-256) of a description of the payment. Used if the description of
+    payment (memo) is too long to naturally fit within the description field
+    of an encoded payment request. When using REST, this field must be encoded
+    as base64.
+    */
+    bytes description_hash = 10;
+
+    // Payment request expiry time in seconds. Default is 86400 (24 hours).
+    int64 expiry = 11;
+
+    // Fallback on-chain address.
+    string fallback_addr = 12;
+
+    // Delta to use for the time-lock of the CLTV extended to the final hop.
+    uint64 cltv_expiry = 13;
+
+    /*
+    Route hints that can each be individually used to assist in reaching the
+    invoice's destination.
+    */
+    repeated RouteHint route_hints = 14;
+
+    // Whether this invoice should include routing hints for private channels.
+    // Note: When enabled, if value and value_msat are zero, a large number of
+    // hints with these channels can be included, which might not be desirable.
+    bool private = 15;
+
+    /*
+    The "add" index of this invoice. Each newly created invoice will increment
+    this index making it monotonically increasing. Callers to the
+    SubscribeInvoices call can use this to instantly get notified of all added
+    invoices with an add_index greater than this one.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    uint64 add_index = 16;
+
+    /*
+    The "settle" index of this invoice. Each newly settled invoice will
+    increment this index making it monotonically increasing. Callers to the
+    SubscribeInvoices call can use this to instantly get notified of all
+    settled invoices with an settle_index greater than this one.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    uint64 settle_index = 17;
+
+    // Deprecated, use amt_paid_sat or amt_paid_msat.
+    int64 amt_paid = 18 [deprecated = true];
+
+    /*
+    The amount that was accepted for this invoice, in satoshis. This will ONLY
+    be set if this invoice has been settled or accepted. We provide this field
+    as if the invoice was created with a zero value, then we need to record what
+    amount was ultimately accepted. Additionally, it's possible that the sender
+    paid MORE that was specified in the original invoice. So we'll record that
+    here as well.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    int64 amt_paid_sat = 19;
+
+    /*
+    The amount that was accepted for this invoice, in millisatoshis. This will
+    ONLY be set if this invoice has been settled or accepted. We provide this
+    field as if the invoice was created with a zero value, then we need to
+    record what amount was ultimately accepted. Additionally, it's possible that
+    the sender paid MORE that was specified in the original invoice. So we'll
+    record that here as well.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    int64 amt_paid_msat = 20;
+
+    enum InvoiceState {
+        OPEN = 0;
+        SETTLED = 1;
+        CANCELED = 2;
+        ACCEPTED = 3;
+    }
+
+    /*
+    The state the invoice is in.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    InvoiceState state = 21;
+
+    /*
+    List of HTLCs paying to this invoice [EXPERIMENTAL].
+    Note: Output only, don't specify for creating an invoice.
+    */
+    repeated InvoiceHTLC htlcs = 22;
+
+    /*
+    List of features advertised on the invoice.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    map<uint32, Feature> features = 24;
+
+    /*
+    Indicates if this invoice was a spontaneous payment that arrived via keysend
+    [EXPERIMENTAL].
+    Note: Output only, don't specify for creating an invoice.
+    */
+    bool is_keysend = 25;
+
+    /*
+    The payment address of this invoice. This is also called payment secret in
+    specifications (e.g. BOLT 11). This value will be used in MPP payments, and
+    also for newer invoices that always require the MPP payload for added
+    end-to-end security.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    bytes payment_addr = 26;
+
+    /*
+    Signals whether or not this is an AMP invoice.
+    */
+    bool is_amp = 27;
+
+    /*
+    [EXPERIMENTAL]:
+
+    Maps a 32-byte hex-encoded set ID to the sub-invoice AMP state for the
+    given set ID. This field is always populated for AMP invoices, and can be
+    used along side LookupInvoice to obtain the HTLC information related to a
+    given sub-invoice.
+    Note: Output only, don't specify for creating an invoice.
+    */
+    map<string, AMPInvoiceState> amp_invoice_state = 28;
+}
+
+enum InvoiceHTLCState {
+    ACCEPTED = 0;
+    SETTLED = 1;
+    CANCELED = 2;
+}
+
+// Details of an HTLC that paid to an invoice
+message InvoiceHTLC {
+    // Short channel id over which the htlc was received.
+    uint64 chan_id = 1 [jstype = JS_STRING];
+
+    // Index identifying the htlc on the channel.
+    uint64 htlc_index = 2;
+
+    // The amount of the htlc in msat.
+    uint64 amt_msat = 3;
+
+    // Block height at which this htlc was accepted.
+    int32 accept_height = 4;
+
+    // Time at which this htlc was accepted.
+    int64 accept_time = 5;
+
+    // Time at which this htlc was settled or canceled.
+    int64 resolve_time = 6;
+
+    // Block height at which this htlc expires.
+    int32 expiry_height = 7;
+
+    // Current state the htlc is in.
+    InvoiceHTLCState state = 8;
+
+    // Custom tlv records.
+    map<uint64, bytes> custom_records = 9;
+
+    // The total amount of the mpp payment in msat.
+    uint64 mpp_total_amt_msat = 10;
+
+    // Details relevant to AMP HTLCs, only populated if this is an AMP HTLC.
+    AMP amp = 11;
+}
+
+// Details specific to AMP HTLCs.
+message AMP {
+    // An n-of-n secret share of the root seed from which child payment hashes
+    // and preimages are derived.
+    bytes root_share = 1;
+
+    // An identifier for the HTLC set that this HTLC belongs to.
+    bytes set_id = 2;
+
+    // A nonce used to randomize the child preimage and child hash from a given
+    // root_share.
+    uint32 child_index = 3;
+
+    // The payment hash of the AMP HTLC.
+    bytes hash = 4;
+
+    // The preimage used to settle this AMP htlc. This field will only be
+    // populated if the invoice is in InvoiceState_ACCEPTED or
+    // InvoiceState_SETTLED.
+    bytes preimage = 5;
+}
+
+message AddInvoiceResponse {
+    bytes r_hash = 1;
+
+    /*
+    A bare-bones invoice for a payment within the Lightning Network. With the
+    details of the invoice, the sender has all the data necessary to send a
+    payment to the recipient.
+    */
+    string payment_request = 2;
+
+    /*
+    The "add" index of this invoice. Each newly created invoice will increment
+    this index making it monotonically increasing. Callers to the
+    SubscribeInvoices call can use this to instantly get notified of all added
+    invoices with an add_index greater than this one.
+    */
+    uint64 add_index = 16;
+
+    /*
+    The payment address of the generated invoice. This is also called
+    payment secret in specifications (e.g. BOLT 11). This value should be used
+    in all payments for this invoice as we require it for end to end security.
+    */
+    bytes payment_addr = 17;
+}
+message PaymentHash {
+    /*
+    The hex-encoded payment hash of the invoice to be looked up. The passed
+    payment hash must be exactly 32 bytes, otherwise an error is returned.
+    Deprecated now that the REST gateway supports base64 encoding of bytes
+    fields.
+    */
+    string r_hash_str = 1 [deprecated = true];
+
+    /*
+    The payment hash of the invoice to be looked up. When using REST, this field
+    must be encoded as base64.
+    */
+    bytes r_hash = 2;
+}
+
+message ListInvoiceRequest {
+    /*
+    If set, only invoices that are not settled and not canceled will be returned
+    in the response.
+    */
+    bool pending_only = 1;
+
+    /*
+    The index of an invoice that will be used as either the start or end of a
+    query to determine which invoices should be returned in the response.
+    */
+    uint64 index_offset = 4;
+
+    // The max number of invoices to return in the response to this query.
+    uint64 num_max_invoices = 5;
+
+    /*
+    If set, the invoices returned will result from seeking backwards from the
+    specified index offset. This can be used to paginate backwards.
+    */
+    bool reversed = 6;
+
+    // If set, returns all invoices with a creation date greater than or equal
+    // to it. Measured in seconds since the unix epoch.
+    uint64 creation_date_start = 7;
+
+    // If set, returns all invoices with a creation date less than or equal to
+    // it. Measured in seconds since the unix epoch.
+    uint64 creation_date_end = 8;
+}
+
+message ListInvoiceResponse {
+    /*
+    A list of invoices from the time slice of the time series specified in the
+    request.
+    */
+    repeated Invoice invoices = 1;
+
+    /*
+    The index of the last item in the set of returned invoices. This can be used
+    to seek further, pagination style.
+    */
+    uint64 last_index_offset = 2;
+
+    /*
+    The index of the last item in the set of returned invoices. This can be used
+    to seek backwards, pagination style.
+    */
+    uint64 first_index_offset = 3;
+}
+
+message InvoiceSubscription {
+    /*
+    If specified (non-zero), then we'll first start by sending out
+    notifications for all added indexes with an add_index greater than this
+    value. This allows callers to catch up on any events they missed while they
+    weren't connected to the streaming RPC.
+    */
+    uint64 add_index = 1;
+
+    /*
+    If specified (non-zero), then we'll first start by sending out
+    notifications for all settled indexes with an settle_index greater than
+    this value. This allows callers to catch up on any events they missed while
+    they weren't connected to the streaming RPC.
+    */
+    uint64 settle_index = 2;
+}
+
+enum PaymentFailureReason {
+    /*
+    Payment isn't failed (yet).
+    */
+    FAILURE_REASON_NONE = 0;
+
+    /*
+    There are more routes to try, but the payment timeout was exceeded.
+    */
+    FAILURE_REASON_TIMEOUT = 1;
+
+    /*
+    All possible routes were tried and failed permanently. Or were no
+    routes to the destination at all.
+    */
+    FAILURE_REASON_NO_ROUTE = 2;
+
+    /*
+    A non-recoverable error has occurred.
+    */
+    FAILURE_REASON_ERROR = 3;
+
+    /*
+    Payment details incorrect (unknown hash, invalid amt or
+    invalid final cltv delta)
+    */
+    FAILURE_REASON_INCORRECT_PAYMENT_DETAILS = 4;
+
+    /*
+    Insufficient local balance.
+    */
+    FAILURE_REASON_INSUFFICIENT_BALANCE = 5;
+}
+
+message Payment {
+    // The payment hash
+    string payment_hash = 1;
+
+    // Deprecated, use value_sat or value_msat.
+    int64 value = 2 [deprecated = true];
+
+    // Deprecated, use creation_time_ns
+    int64 creation_date = 3 [deprecated = true];
+
+    reserved 4;
+
+    // Deprecated, use fee_sat or fee_msat.
+    int64 fee = 5 [deprecated = true];
+
+    // The payment preimage
+    string payment_preimage = 6;
+
+    // The value of the payment in satoshis
+    int64 value_sat = 7;
+
+    // The value of the payment in milli-satoshis
+    int64 value_msat = 8;
+
+    // The optional payment request being fulfilled.
+    string payment_request = 9;
+
+    enum PaymentStatus {
+        // Deprecated. This status will never be returned.
+        UNKNOWN = 0 [deprecated = true];
+
+        // Payment has inflight HTLCs.
+        IN_FLIGHT = 1;
+
+        // Payment is settled.
+        SUCCEEDED = 2;
+
+        // Payment is failed.
+        FAILED = 3;
+
+        // Payment is created and has not attempted any HTLCs.
+        INITIATED = 4;
+    }
+
+    // The status of the payment.
+    PaymentStatus status = 10;
+
+    //  The fee paid for this payment in satoshis
+    int64 fee_sat = 11;
+
+    //  The fee paid for this payment in milli-satoshis
+    int64 fee_msat = 12;
+
+    // The time in UNIX nanoseconds at which the payment was created.
+    int64 creation_time_ns = 13;
+
+    // The HTLCs made in attempt to settle the payment.
+    repeated HTLCAttempt htlcs = 14;
+
+    /*
+    The creation index of this payment. Each payment can be uniquely identified
+    by this index, which may not strictly increment by 1 for payments made in
+    older versions of lnd.
+    */
+    uint64 payment_index = 15;
+
+    PaymentFailureReason failure_reason = 16;
+}
+
+message HTLCAttempt {
+    // The unique ID that is used for this attempt.
+    uint64 attempt_id = 7;
+
+    enum HTLCStatus {
+        IN_FLIGHT = 0;
+        SUCCEEDED = 1;
+        FAILED = 2;
+    }
+
+    // The status of the HTLC.
+    HTLCStatus status = 1;
+
+    // The route taken by this HTLC.
+    Route route = 2;
+
+    // The time in UNIX nanoseconds at which this HTLC was sent.
+    int64 attempt_time_ns = 3;
+
+    /*
+    The time in UNIX nanoseconds at which this HTLC was settled or failed.
+    This value will not be set if the HTLC is still IN_FLIGHT.
+    */
+    int64 resolve_time_ns = 4;
+
+    // Detailed htlc failure info.
+    Failure failure = 5;
+
+    // The preimage that was used to settle the HTLC.
+    bytes preimage = 6;
+}
+
+message ListPaymentsRequest {
+    /*
+    If true, then return payments that have not yet fully completed. This means
+    that pending payments, as well as failed payments will show up if this
+    field is set to true. This flag doesn't change the meaning of the indices,
+    which are tied to individual payments.
+    */
+    bool include_incomplete = 1;
+
+    /*
+    The index of a payment that will be used as either the start or end of a
+    query to determine which payments should be returned in the response. The
+    index_offset is exclusive. In the case of a zero index_offset, the query
+    will start with the oldest payment when paginating forwards, or will end
+    with the most recent payment when paginating backwards.
+    */
+    uint64 index_offset = 2;
+
+    // The maximal number of payments returned in the response to this query.
+    uint64 max_payments = 3;
+
+    /*
+    If set, the payments returned will result from seeking backwards from the
+    specified index offset. This can be used to paginate backwards. The order
+    of the returned payments is always oldest first (ascending index order).
+    */
+    bool reversed = 4;
+
+    /*
+    If set, all payments (complete and incomplete, independent of the
+    max_payments parameter) will be counted. Note that setting this to true will
+    increase the run time of the call significantly on systems that have a lot
+    of payments, as all of them have to be iterated through to be counted.
+    */
+    bool count_total_payments = 5;
+
+    // If set, returns all payments with a creation date greater than or equal
+    // to it. Measured in seconds since the unix epoch.
+    uint64 creation_date_start = 6;
+
+    // If set, returns all payments with a creation date less than or equal to
+    // it. Measured in seconds since the unix epoch.
+    uint64 creation_date_end = 7;
+}
+
+message ListPaymentsResponse {
+    // The list of payments
+    repeated Payment payments = 1;
+
+    /*
+    The index of the first item in the set of returned payments. This can be
+    used as the index_offset to continue seeking backwards in the next request.
+    */
+    uint64 first_index_offset = 2;
+
+    /*
+    The index of the last item in the set of returned payments. This can be used
+    as the index_offset to continue seeking forwards in the next request.
+    */
+    uint64 last_index_offset = 3;
+
+    /*
+    Will only be set if count_total_payments in the request was set. Represents
+    the total number of payments (complete and incomplete, independent of the
+    number of payments requested in the query) currently present in the payments
+    database.
+    */
+    uint64 total_num_payments = 4;
+}
+
+message DeletePaymentRequest {
+    // Payment hash to delete.
+    bytes payment_hash = 1;
+
+    /*
+    Only delete failed HTLCs from the payment, not the payment itself.
+    */
+    bool failed_htlcs_only = 2;
+}
+
+message DeleteAllPaymentsRequest {
+    // Only delete failed payments.
+    bool failed_payments_only = 1;
+
+    /*
+    Only delete failed HTLCs from payments, not the payment itself.
+    */
+    bool failed_htlcs_only = 2;
+
+    // Delete all payments. NOTE: Using this option requires careful
+    // consideration as it is a destructive operation.
+    bool all_payments = 3;
+}
+
+message DeletePaymentResponse {
+}
+
+message DeleteAllPaymentsResponse {
+}
+
+message AbandonChannelRequest {
+    ChannelPoint channel_point = 1;
+
+    bool pending_funding_shim_only = 2;
+
+    /*
+    Override the requirement for being in dev mode by setting this to true and
+    confirming the user knows what they are doing and this is a potential foot
+    gun to lose funds if used on active channels.
+    */
+    bool i_know_what_i_am_doing = 3;
+}
+
+message AbandonChannelResponse {
+}
+
+message DebugLevelRequest {
+    bool show = 1;
+    string level_spec = 2;
+}
+message DebugLevelResponse {
+    string sub_systems = 1;
+}
+
+message PayReqString {
+    // The payment request string to be decoded
+    string pay_req = 1;
+}
+message PayReq {
+    string destination = 1;
+    string payment_hash = 2;
+    int64 num_satoshis = 3;
+    int64 timestamp = 4;
+    int64 expiry = 5;
+    string description = 6;
+    string description_hash = 7;
+    string fallback_addr = 8;
+    int64 cltv_expiry = 9;
+    repeated RouteHint route_hints = 10;
+    bytes payment_addr = 11;
+    int64 num_msat = 12;
+    map<uint32, Feature> features = 13;
+    repeated BlindedPaymentPath blinded_paths = 14;
+}
+
+enum FeatureBit {
+    DATALOSS_PROTECT_REQ = 0;
+    DATALOSS_PROTECT_OPT = 1;
+    INITIAL_ROUING_SYNC = 3;
+    UPFRONT_SHUTDOWN_SCRIPT_REQ = 4;
+    UPFRONT_SHUTDOWN_SCRIPT_OPT = 5;
+    GOSSIP_QUERIES_REQ = 6;
+    GOSSIP_QUERIES_OPT = 7;
+    TLV_ONION_REQ = 8;
+    TLV_ONION_OPT = 9;
+    EXT_GOSSIP_QUERIES_REQ = 10;
+    EXT_GOSSIP_QUERIES_OPT = 11;
+    STATIC_REMOTE_KEY_REQ = 12;
+    STATIC_REMOTE_KEY_OPT = 13;
+    PAYMENT_ADDR_REQ = 14;
+    PAYMENT_ADDR_OPT = 15;
+    MPP_REQ = 16;
+    MPP_OPT = 17;
+    WUMBO_CHANNELS_REQ = 18;
+    WUMBO_CHANNELS_OPT = 19;
+    ANCHORS_REQ = 20;
+    ANCHORS_OPT = 21;
+    ANCHORS_ZERO_FEE_HTLC_REQ = 22;
+    ANCHORS_ZERO_FEE_HTLC_OPT = 23;
+    ROUTE_BLINDING_REQUIRED = 24;
+    ROUTE_BLINDING_OPTIONAL = 25;
+    AMP_REQ = 30;
+    AMP_OPT = 31;
+}
+
+message Feature {
+    string name = 2;
+    bool is_required = 3;
+    bool is_known = 4;
+}
+
+message FeeReportRequest {
+}
+message ChannelFeeReport {
+    // The short channel id that this fee report belongs to.
+    uint64 chan_id = 5 [jstype = JS_STRING];
+
+    // The channel that this fee report belongs to.
+    string channel_point = 1;
+
+    // The base fee charged regardless of the number of milli-satoshis sent.
+    int64 base_fee_msat = 2;
+
+    // The amount charged per milli-satoshis transferred expressed in
+    // millionths of a satoshi.
+    int64 fee_per_mil = 3;
+
+    // The effective fee rate in milli-satoshis. Computed by dividing the
+    // fee_per_mil value by 1 million.
+    double fee_rate = 4;
+
+    // The base fee charged regardless of the number of milli-satoshis sent.
+    int32 inbound_base_fee_msat = 6;
+
+    // The amount charged per milli-satoshis transferred expressed in
+    // millionths of a satoshi.
+    int32 inbound_fee_per_mil = 7;
+}
+
+message FeeReportResponse {
+    // An array of channel fee reports which describes the current fee schedule
+    // for each channel.
+    repeated ChannelFeeReport channel_fees = 1;
+
+    // The total amount of fee revenue (in satoshis) the switch has collected
+    // over the past 24 hrs.
+    uint64 day_fee_sum = 2;
+
+    // The total amount of fee revenue (in satoshis) the switch has collected
+    // over the past 1 week.
+    uint64 week_fee_sum = 3;
+
+    // The total amount of fee revenue (in satoshis) the switch has collected
+    // over the past 1 month.
+    uint64 month_fee_sum = 4;
+}
+
+message InboundFee {
+    // The inbound base fee charged regardless of the number of milli-satoshis
+    // received in the channel. By default, only negative values are accepted.
+    int32 base_fee_msat = 1;
+
+    // The effective inbound fee rate in micro-satoshis (parts per million).
+    // By default, only negative values are accepted.
+    int32 fee_rate_ppm = 2;
+}
+
+message PolicyUpdateRequest {
+    oneof scope {
+        // If set, then this update applies to all currently active channels.
+        bool global = 1;
+
+        // If set, this update will target a specific channel.
+        ChannelPoint chan_point = 2;
+    }
+
+    // The base fee charged regardless of the number of milli-satoshis sent.
+    int64 base_fee_msat = 3;
+
+    // The effective fee rate in milli-satoshis. The precision of this value
+    // goes up to 6 decimal places, so 1e-6.
+    double fee_rate = 4;
+
+    // The effective fee rate in micro-satoshis (parts per million).
+    uint32 fee_rate_ppm = 9;
+
+    // The required timelock delta for HTLCs forwarded over the channel.
+    uint32 time_lock_delta = 5;
+
+    // If set, the maximum HTLC size in milli-satoshis. If unset, the maximum
+    // HTLC will be unchanged.
+    uint64 max_htlc_msat = 6;
+
+    // The minimum HTLC size in milli-satoshis. Only applied if
+    // min_htlc_msat_specified is true.
+    uint64 min_htlc_msat = 7;
+
+    // If true, min_htlc_msat is applied.
+    bool min_htlc_msat_specified = 8;
+
+    // Optional inbound fee. If unset, the previously set value will be
+    // retained [EXPERIMENTAL].
+    InboundFee inbound_fee = 10;
+}
+
+enum UpdateFailure {
+    UPDATE_FAILURE_UNKNOWN = 0;
+    UPDATE_FAILURE_PENDING = 1;
+    UPDATE_FAILURE_NOT_FOUND = 2;
+    UPDATE_FAILURE_INTERNAL_ERR = 3;
+    UPDATE_FAILURE_INVALID_PARAMETER = 4;
+}
+
+message FailedUpdate {
+    // The outpoint in format txid:n
+    OutPoint outpoint = 1;
+
+    // Reason for the policy update failure.
+    UpdateFailure reason = 2;
+
+    // A string representation of the policy update error.
+    string update_error = 3;
+}
+
+message PolicyUpdateResponse {
+    // List of failed policy updates.
+    repeated FailedUpdate failed_updates = 1;
+}
+
+message ForwardingHistoryRequest {
+    // Start time is the starting point of the forwarding history request. All
+    // records beyond this point will be included, respecting the end time, and
+    // the index offset.
+    uint64 start_time = 1;
+
+    // End time is the end point of the forwarding history request. The
+    // response will carry at most 50k records between the start time and the
+    // end time. The index offset can be used to implement pagination.
+    uint64 end_time = 2;
+
+    // Index offset is the offset in the time series to start at. As each
+    // response can only contain 50k records, callers can use this to skip
+    // around within a packed time series.
+    uint32 index_offset = 3;
+
+    // The max number of events to return in the response to this query.
+    uint32 num_max_events = 4;
+
+    // Informs the server if the peer alias should be looked up for each
+    // forwarding event.
+    bool peer_alias_lookup = 5;
+}
+message ForwardingEvent {
+    // Timestamp is the time (unix epoch offset) that this circuit was
+    // completed. Deprecated by timestamp_ns.
+    uint64 timestamp = 1 [deprecated = true];
+
+    // The incoming channel ID that carried the HTLC that created the circuit.
+    uint64 chan_id_in = 2 [jstype = JS_STRING];
+
+    // The outgoing channel ID that carried the preimage that completed the
+    // circuit.
+    uint64 chan_id_out = 4 [jstype = JS_STRING];
+
+    // The total amount (in satoshis) of the incoming HTLC that created half
+    // the circuit.
+    uint64 amt_in = 5;
+
+    // The total amount (in satoshis) of the outgoing HTLC that created the
+    // second half of the circuit.
+    uint64 amt_out = 6;
+
+    // The total fee (in satoshis) that this payment circuit carried.
+    uint64 fee = 7;
+
+    // The total fee (in milli-satoshis) that this payment circuit carried.
+    uint64 fee_msat = 8;
+
+    // The total amount (in milli-satoshis) of the incoming HTLC that created
+    // half the circuit.
+    uint64 amt_in_msat = 9;
+
+    // The total amount (in milli-satoshis) of the outgoing HTLC that created
+    // the second half of the circuit.
+    uint64 amt_out_msat = 10;
+
+    // The number of nanoseconds elapsed since January 1, 1970 UTC when this
+    // circuit was completed.
+    uint64 timestamp_ns = 11;
+
+    // The peer alias of the incoming channel.
+    string peer_alias_in = 12;
+
+    // The peer alias of the outgoing channel.
+    string peer_alias_out = 13;
+
+    // TODO(roasbeef): add settlement latency?
+    //  * use FPE on the chan id?
+    //  * also list failures?
+}
+message ForwardingHistoryResponse {
+    // A list of forwarding events from the time slice of the time series
+    // specified in the request.
+    repeated ForwardingEvent forwarding_events = 1;
+
+    // The index of the last time in the set of returned forwarding events. Can
+    // be used to seek further, pagination style.
+    uint32 last_offset_index = 2;
+}
+
+message ExportChannelBackupRequest {
+    // The target channel point to obtain a back up for.
+    ChannelPoint chan_point = 1;
+}
+
+message ChannelBackup {
+    /*
+    Identifies the channel that this backup belongs to.
+    */
+    ChannelPoint chan_point = 1;
+
+    /*
+    Is an encrypted single-chan backup. this can be passed to
+    RestoreChannelBackups, or the WalletUnlocker Init and Unlock methods in
+    order to trigger the recovery protocol. When using REST, this field must be
+    encoded as base64.
+    */
+    bytes chan_backup = 2;
+}
+
+message MultiChanBackup {
+    /*
+    Is the set of all channels that are included in this multi-channel backup.
+    */
+    repeated ChannelPoint chan_points = 1;
+
+    /*
+    A single encrypted blob containing all the static channel backups of the
+    channel listed above. This can be stored as a single file or blob, and
+    safely be replaced with any prior/future versions. When using REST, this
+    field must be encoded as base64.
+    */
+    bytes multi_chan_backup = 2;
+}
+
+message ChanBackupExportRequest {
+}
+message ChanBackupSnapshot {
+    /*
+    The set of new channels that have been added since the last channel backup
+    snapshot was requested.
+    */
+    ChannelBackups single_chan_backups = 1;
+
+    /*
+    A multi-channel backup that covers all open channels currently known to
+    lnd.
+    */
+    MultiChanBackup multi_chan_backup = 2;
+}
+
+message ChannelBackups {
+    /*
+    A set of single-chan static channel backups.
+    */
+    repeated ChannelBackup chan_backups = 1;
+}
+
+message RestoreChanBackupRequest {
+    oneof backup {
+        /*
+        The channels to restore as a list of channel/backup pairs.
+        */
+        ChannelBackups chan_backups = 1;
+
+        /*
+        The channels to restore in the packed multi backup format. When using
+        REST, this field must be encoded as base64.
+        */
+        bytes multi_chan_backup = 2;
+    }
+}
+message RestoreBackupResponse {
+}
+
+message ChannelBackupSubscription {
+}
+
+message VerifyChanBackupResponse {
+}
+
+message MacaroonPermission {
+    // The entity a permission grants access to.
+    string entity = 1;
+
+    // The action that is granted.
+    string action = 2;
+}
+message BakeMacaroonRequest {
+    // The list of permissions the new macaroon should grant.
+    repeated MacaroonPermission permissions = 1;
+
+    // The root key ID used to create the macaroon, must be a positive integer.
+    uint64 root_key_id = 2;
+
+    /*
+    Informs the RPC on whether to allow external permissions that LND is not
+    aware of.
+    */
+    bool allow_external_permissions = 3;
+}
+message BakeMacaroonResponse {
+    // The hex encoded macaroon, serialized in binary format.
+    string macaroon = 1;
+}
+
+message ListMacaroonIDsRequest {
+}
+message ListMacaroonIDsResponse {
+    // The list of root key IDs that are in use.
+    repeated uint64 root_key_ids = 1;
+}
+
+message DeleteMacaroonIDRequest {
+    // The root key ID to be removed.
+    uint64 root_key_id = 1;
+}
+message DeleteMacaroonIDResponse {
+    // A boolean indicates that the deletion is successful.
+    bool deleted = 1;
+}
+
+message MacaroonPermissionList {
+    // A list of macaroon permissions.
+    repeated MacaroonPermission permissions = 1;
+}
+
+message ListPermissionsRequest {
+}
+message ListPermissionsResponse {
+    /*
+    A map between all RPC method URIs and their required macaroon permissions to
+    access them.
+    */
+    map<string, MacaroonPermissionList> method_permissions = 1;
+}
+
+message Failure {
+    enum FailureCode {
+        /*
+        The numbers assigned in this enumeration match the failure codes as
+        defined in BOLT #4. Because protobuf 3 requires enums to start with 0,
+        a RESERVED value is added.
+        */
+        RESERVED = 0;
+
+        INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS = 1;
+        INCORRECT_PAYMENT_AMOUNT = 2;
+        FINAL_INCORRECT_CLTV_EXPIRY = 3;
+        FINAL_INCORRECT_HTLC_AMOUNT = 4;
+        FINAL_EXPIRY_TOO_SOON = 5;
+        INVALID_REALM = 6;
+        EXPIRY_TOO_SOON = 7;
+        INVALID_ONION_VERSION = 8;
+        INVALID_ONION_HMAC = 9;
+        INVALID_ONION_KEY = 10;
+        AMOUNT_BELOW_MINIMUM = 11;
+        FEE_INSUFFICIENT = 12;
+        INCORRECT_CLTV_EXPIRY = 13;
+        CHANNEL_DISABLED = 14;
+        TEMPORARY_CHANNEL_FAILURE = 15;
+        REQUIRED_NODE_FEATURE_MISSING = 16;
+        REQUIRED_CHANNEL_FEATURE_MISSING = 17;
+        UNKNOWN_NEXT_PEER = 18;
+        TEMPORARY_NODE_FAILURE = 19;
+        PERMANENT_NODE_FAILURE = 20;
+        PERMANENT_CHANNEL_FAILURE = 21;
+        EXPIRY_TOO_FAR = 22;
+        MPP_TIMEOUT = 23;
+        INVALID_ONION_PAYLOAD = 24;
+        INVALID_ONION_BLINDING = 25;
+
+        /*
+        An internal error occurred.
+        */
+        INTERNAL_FAILURE = 997;
+
+        /*
+        The error source is known, but the failure itself couldn't be decoded.
+        */
+        UNKNOWN_FAILURE = 998;
+
+        /*
+        An unreadable failure result is returned if the received failure message
+        cannot be decrypted. In that case the error source is unknown.
+        */
+        UNREADABLE_FAILURE = 999;
+    }
+
+    // Failure code as defined in the Lightning spec
+    FailureCode code = 1;
+
+    reserved 2;
+
+    // An optional channel update message.
+    ChannelUpdate channel_update = 3;
+
+    // A failure type-dependent htlc value.
+    uint64 htlc_msat = 4;
+
+    // The sha256 sum of the onion payload.
+    bytes onion_sha_256 = 5;
+
+    // A failure type-dependent cltv expiry value.
+    uint32 cltv_expiry = 6;
+
+    // A failure type-dependent flags value.
+    uint32 flags = 7;
+
+    /*
+    The position in the path of the intermediate or final node that generated
+    the failure message. Position zero is the sender node.
+    **/
+    uint32 failure_source_index = 8;
+
+    // A failure type-dependent block height.
+    uint32 height = 9;
+}
+
+message ChannelUpdate {
+    /*
+    The signature that validates the announced data and proves the ownership
+    of node id.
+    */
+    bytes signature = 1;
+
+    /*
+    The target chain that this channel was opened within. This value
+    should be the genesis hash of the target chain. Along with the short
+    channel ID, this uniquely identifies the channel globally in a
+    blockchain.
+    */
+    bytes chain_hash = 2;
+
+    /*
+    The unique description of the funding transaction.
+    */
+    uint64 chan_id = 3 [jstype = JS_STRING];
+
+    /*
+    A timestamp that allows ordering in the case of multiple announcements.
+    We should ignore the message if timestamp is not greater than the
+    last-received.
+    */
+    uint32 timestamp = 4;
+
+    /*
+    The bitfield that describes whether optional fields are present in this
+    update. Currently, the least-significant bit must be set to 1 if the
+    optional field MaxHtlc is present.
+    */
+    uint32 message_flags = 10;
+
+    /*
+    The bitfield that describes additional meta-data concerning how the
+    update is to be interpreted. Currently, the least-significant bit must be
+    set to 0 if the creating node corresponds to the first node in the
+    previously sent channel announcement and 1 otherwise. If the second bit
+    is set, then the channel is set to be disabled.
+    */
+    uint32 channel_flags = 5;
+
+    /*
+    The minimum number of blocks this node requires to be added to the expiry
+    of HTLCs. This is a security parameter determined by the node operator.
+    This value represents the required gap between the time locks of the
+    incoming and outgoing HTLC's set to this node.
+    */
+    uint32 time_lock_delta = 6;
+
+    /*
+    The minimum HTLC value which will be accepted.
+    */
+    uint64 htlc_minimum_msat = 7;
+
+    /*
+    The base fee that must be used for incoming HTLC's to this particular
+    channel. This value will be tacked onto the required for a payment
+    independent of the size of the payment.
+    */
+    uint32 base_fee = 8;
+
+    /*
+    The fee rate that will be charged per millionth of a satoshi.
+    */
+    uint32 fee_rate = 9;
+
+    /*
+    The maximum HTLC value which will be accepted.
+    */
+    uint64 htlc_maximum_msat = 11;
+
+    /*
+    The set of data that was appended to this message, some of which we may
+    not actually know how to iterate or parse. By holding onto this data, we
+    ensure that we're able to properly validate the set of signatures that
+    cover these new fields, and ensure we're able to make upgrades to the
+    network in a forwards compatible manner.
+    */
+    bytes extra_opaque_data = 12;
+}
+
+message MacaroonId {
+    bytes nonce = 1;
+    bytes storageId = 2;
+    repeated Op ops = 3;
+}
+
+message Op {
+    string entity = 1;
+    repeated string actions = 2;
+}
+
+message CheckMacPermRequest {
+    bytes macaroon = 1;
+    repeated MacaroonPermission permissions = 2;
+    string fullMethod = 3;
+}
+
+message CheckMacPermResponse {
+    bool valid = 1;
+}
+
+message RPCMiddlewareRequest {
+    /*
+    The unique ID of the intercepted original gRPC request. Useful for mapping
+    request to response when implementing full duplex message interception. For
+    streaming requests, this will be the same ID for all incoming and outgoing
+    middleware intercept messages of the _same_ stream.
+    */
+    uint64 request_id = 1;
+
+    /*
+    The raw bytes of the complete macaroon as sent by the gRPC client in the
+    original request. This might be empty for a request that doesn't require
+    macaroons such as the wallet unlocker RPCs.
+    */
+    bytes raw_macaroon = 2;
+
+    /*
+    The parsed condition of the macaroon's custom caveat for convenient access.
+    This field only contains the value of the custom caveat that the handling
+    middleware has registered itself for. The condition _must_ be validated for
+    messages of intercept_type stream_auth and request!
+    */
+    string custom_caveat_condition = 3;
+
+    /*
+    There are three types of messages that will be sent to the middleware for
+    inspection and approval: Stream authentication, request and response
+    interception. The first two can only be accepted (=forward to main RPC
+    server) or denied (=return error to client). Intercepted responses can also
+    be replaced/overwritten.
+    */
+    oneof intercept_type {
+        /*
+        Intercept stream authentication: each new streaming RPC call that is
+        initiated against lnd and contains the middleware's custom macaroon
+        caveat can be approved or denied based upon the macaroon in the stream
+        header. This message will only be sent for streaming RPCs, unary RPCs
+        must handle the macaroon authentication in the request interception to
+        avoid an additional message round trip between lnd and the middleware.
+        */
+        StreamAuth stream_auth = 4;
+
+        /*
+        Intercept incoming gRPC client request message: all incoming messages,
+        both on streaming and unary RPCs, are forwarded to the middleware for
+        inspection. For unary RPC messages the middleware is also expected to
+        validate the custom macaroon caveat of the request.
+        */
+        RPCMessage request = 5;
+
+        /*
+        Intercept outgoing gRPC response message: all outgoing messages, both on
+        streaming and unary RPCs, are forwarded to the middleware for inspection
+        and amendment. The response in this message is the original response as
+        it was generated by the main RPC server. It can either be accepted
+        (=forwarded to the client), replaced/overwritten with a new message of
+        the same type, or replaced by an error message.
+        */
+        RPCMessage response = 6;
+
+        /*
+        This is used to indicate to the client that the server has successfully
+        registered the interceptor. This is only used in the very first message
+        that the server sends to the client after the client sends the server
+        the middleware registration message.
+        */
+        bool reg_complete = 8;
+    }
+
+    /*
+    The unique message ID of this middleware intercept message. There can be
+    multiple middleware intercept messages per single gRPC request (one for the
+    incoming request and one for the outgoing response) or gRPC stream (one for
+    each incoming message and one for each outgoing response). This message ID
+    must be referenced when responding (accepting/rejecting/modifying) to an
+    intercept message.
+    */
+    uint64 msg_id = 7;
+}
+
+message StreamAuth {
+    /*
+    The full URI (in the format /<rpcpackage>.<ServiceName>/MethodName, for
+    example /lnrpc.Lightning/GetInfo) of the streaming RPC method that was just
+    established.
+    */
+    string method_full_uri = 1;
+}
+
+message RPCMessage {
+    /*
+    The full URI (in the format /<rpcpackage>.<ServiceName>/MethodName, for
+    example /lnrpc.Lightning/GetInfo) of the RPC method the message was sent
+    to/from.
+    */
+    string method_full_uri = 1;
+
+    /*
+    Indicates whether the message was sent over a streaming RPC method or not.
+    */
+    bool stream_rpc = 2;
+
+    /*
+    The full canonical gRPC name of the message type (in the format
+    <rpcpackage>.TypeName, for example lnrpc.GetInfoRequest). In case of an
+    error being returned from lnd, this simply contains the string "error".
+    */
+    string type_name = 3;
+
+    /*
+    The full content of the gRPC message, serialized in the binary protobuf
+    format.
+    */
+    bytes serialized = 4;
+
+    /*
+    Indicates that the response from lnd was an error, not a gRPC response. If
+    this is set to true then the type_name contains the string "error" and
+    serialized contains the error string.
+    */
+    bool is_error = 5;
+}
+
+message RPCMiddlewareResponse {
+    /*
+    The request message ID this response refers to. Must always be set when
+    giving feedback to an intercept but is ignored for the initial registration
+    message.
+    */
+    uint64 ref_msg_id = 1;
+
+    /*
+    The middleware can only send two types of messages to lnd: The initial
+    registration message that identifies the middleware and after that only
+    feedback messages to requests sent to the middleware.
+    */
+    oneof middleware_message {
+        /*
+        The registration message identifies the middleware that's being
+        registered in lnd. The registration message must be sent immediately
+        after initiating the RegisterRpcMiddleware stream, otherwise lnd will
+        time out the attempt and terminate the request. NOTE: The middleware
+        will only receive interception messages for requests that contain a
+        macaroon with the custom caveat that the middleware declares it is
+        responsible for handling in the registration message! As a security
+        measure, _no_ middleware can intercept requests made with _unencumbered_
+        macaroons!
+        */
+        MiddlewareRegistration register = 2;
+
+        /*
+        The middleware received an interception request and gives feedback to
+        it. The request_id indicates what message the feedback refers to.
+        */
+        InterceptFeedback feedback = 3;
+    }
+}
+
+message MiddlewareRegistration {
+    /*
+    The name of the middleware to register. The name should be as informative
+    as possible and is logged on registration.
+    */
+    string middleware_name = 1;
+
+    /*
+    The name of the custom macaroon caveat that this middleware is responsible
+    for. Only requests/responses that contain a macaroon with the registered
+    custom caveat are forwarded for interception to the middleware. The
+    exception being the read-only mode: All requests/responses are forwarded to
+    a middleware that requests read-only access but such a middleware won't be
+    allowed to _alter_ responses. As a security measure, _no_ middleware can
+    change responses to requests made with _unencumbered_ macaroons!
+    NOTE: Cannot be used at the same time as read_only_mode.
+    */
+    string custom_macaroon_caveat_name = 2;
+
+    /*
+    Instead of defining a custom macaroon caveat name a middleware can register
+    itself for read-only access only. In that mode all requests/responses are
+    forwarded to the middleware but the middleware isn't allowed to alter any of
+    the responses.
+    NOTE: Cannot be used at the same time as custom_macaroon_caveat_name.
+    */
+    bool read_only_mode = 3;
+}
+
+message InterceptFeedback {
+    /*
+    The error to return to the user. If this is non-empty, the incoming gRPC
+    stream/request is aborted and the error is returned to the gRPC client. If
+    this value is empty, it means the middleware accepts the stream/request/
+    response and the processing of it can continue.
+    */
+    string error = 1;
+
+    /*
+    A boolean indicating that the gRPC message should be replaced/overwritten.
+    This boolean is needed because in protobuf an empty message is serialized as
+    a 0-length or nil byte slice and we wouldn't be able to distinguish between
+    an empty replacement message and the "don't replace anything" case.
+    */
+    bool replace_response = 2;
+
+    /*
+    If the replace_response field is set to true, this field must contain the
+    binary serialized gRPC message in the protobuf format.
+    */
+    bytes replacement_serialized = 3;
+}

+ 9 - 0
crates/cdk-lnd/src/proto/mod.rs

@@ -0,0 +1,9 @@
+#[allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)]
+pub(crate) mod lnrpc {
+    tonic::include_proto!("lnrpc");
+}
+
+#[allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)]
+pub(crate) mod routerrpc {
+    tonic::include_proto!("routerrpc");
+}

+ 1023 - 0
crates/cdk-lnd/src/proto/routerrpc.proto

@@ -0,0 +1,1023 @@
+syntax = "proto3";
+
+package routerrpc;
+
+import "lnrpc.proto";
+
+option go_package = "github.com/lightningnetwork/lnd/lnrpc/routerrpc";
+
+/*
+ * Comments in this file will be directly parsed into the API
+ * Documentation as descriptions of the associated method, message, or field.
+ * These descriptions should go right above the definition of the object, and
+ * can be in either block or // comment format.
+ *
+ * An RPC method can be matched to an lncli command by placing a line in the
+ * beginning of the description in exactly the following format:
+ * lncli: `methodname`
+ *
+ * Failure to specify the exact name of the command will cause documentation
+ * generation to fail.
+ *
+ * More information on how exactly the gRPC documentation is generated from
+ * this proto file can be found here:
+ * https://github.com/lightninglabs/lightning-api
+ */
+
+// Router is a service that offers advanced interaction with the router
+// subsystem of the daemon.
+service Router {
+    /*
+    SendPaymentV2 attempts to route a payment described by the passed
+    PaymentRequest to the final destination. The call returns a stream of
+    payment updates. When using this RPC, make sure to set a fee limit, as the
+    default routing fee limit is 0 sats. Without a non-zero fee limit only
+    routes without fees will be attempted which often fails with
+    FAILURE_REASON_NO_ROUTE.
+    */
+    rpc SendPaymentV2 (SendPaymentRequest) returns (stream lnrpc.Payment);
+
+    /* lncli: `trackpayment`
+    TrackPaymentV2 returns an update stream for the payment identified by the
+    payment hash.
+    */
+    rpc TrackPaymentV2 (TrackPaymentRequest) returns (stream lnrpc.Payment);
+
+    /*
+    TrackPayments returns an update stream for every payment that is not in a
+    terminal state. Note that if payments are in-flight while starting a new
+    subscription, the start of the payment stream could produce out-of-order
+    and/or duplicate events. In order to get updates for every in-flight
+    payment attempt make sure to subscribe to this method before initiating any
+    payments.
+    */
+    rpc TrackPayments (TrackPaymentsRequest) returns (stream lnrpc.Payment);
+
+    /*
+    EstimateRouteFee allows callers to obtain a lower bound w.r.t how much it
+    may cost to send an HTLC to the target end destination.
+    */
+    rpc EstimateRouteFee (RouteFeeRequest) returns (RouteFeeResponse);
+
+    /*
+    Deprecated, use SendToRouteV2. SendToRoute attempts to make a payment via
+    the specified route. This method differs from SendPayment in that it
+    allows users to specify a full route manually. This can be used for
+    things like rebalancing, and atomic swaps. It differs from the newer
+    SendToRouteV2 in that it doesn't return the full HTLC information.
+    */
+    rpc SendToRoute (SendToRouteRequest) returns (SendToRouteResponse) {
+        option deprecated = true;
+    }
+
+    /*
+    SendToRouteV2 attempts to make a payment via the specified route. This
+    method differs from SendPayment in that it allows users to specify a full
+    route manually. This can be used for things like rebalancing, and atomic
+    swaps.
+    */
+    rpc SendToRouteV2 (SendToRouteRequest) returns (lnrpc.HTLCAttempt);
+
+    /* lncli: `resetmc`
+    ResetMissionControl clears all mission control state and starts with a clean
+    slate.
+    */
+    rpc ResetMissionControl (ResetMissionControlRequest)
+        returns (ResetMissionControlResponse);
+
+    /* lncli: `querymc`
+    QueryMissionControl exposes the internal mission control state to callers.
+    It is a development feature.
+    */
+    rpc QueryMissionControl (QueryMissionControlRequest)
+        returns (QueryMissionControlResponse);
+
+    /* lncli: `importmc`
+    XImportMissionControl is an experimental API that imports the state provided
+    to the internal mission control's state, using all results which are more
+    recent than our existing values. These values will only be imported
+    in-memory, and will not be persisted across restarts.
+    */
+    rpc XImportMissionControl (XImportMissionControlRequest)
+        returns (XImportMissionControlResponse);
+
+    /* lncli: `getmccfg`
+    GetMissionControlConfig returns mission control's current config.
+    */
+    rpc GetMissionControlConfig (GetMissionControlConfigRequest)
+        returns (GetMissionControlConfigResponse);
+
+    /* lncli: `setmccfg`
+    SetMissionControlConfig will set mission control's config, if the config
+    provided is valid.
+    */
+    rpc SetMissionControlConfig (SetMissionControlConfigRequest)
+        returns (SetMissionControlConfigResponse);
+
+    /* lncli: `queryprob`
+    Deprecated. QueryProbability returns the current success probability
+    estimate for a given node pair and amount. The call returns a zero success
+    probability if no channel is available or if the amount violates min/max
+    HTLC constraints.
+    */
+    rpc QueryProbability (QueryProbabilityRequest)
+        returns (QueryProbabilityResponse);
+
+    /* lncli: `buildroute`
+    BuildRoute builds a fully specified route based on a list of hop public
+    keys. It retrieves the relevant channel policies from the graph in order to
+    calculate the correct fees and time locks.
+    Note that LND will use its default final_cltv_delta if no value is supplied.
+    Make sure to add the correct final_cltv_delta depending on the invoice
+    restriction. Moreover the caller has to make sure to provide the
+    payment_addr if the route is paying an invoice which signaled it.
+    */
+    rpc BuildRoute (BuildRouteRequest) returns (BuildRouteResponse);
+
+    /*
+    SubscribeHtlcEvents creates a uni-directional stream from the server to
+    the client which delivers a stream of htlc events.
+    */
+    rpc SubscribeHtlcEvents (SubscribeHtlcEventsRequest)
+        returns (stream HtlcEvent);
+
+    /*
+    Deprecated, use SendPaymentV2. SendPayment attempts to route a payment
+    described by the passed PaymentRequest to the final destination. The call
+    returns a stream of payment status updates.
+    */
+    rpc SendPayment (SendPaymentRequest) returns (stream PaymentStatus) {
+        option deprecated = true;
+    }
+
+    /*
+    Deprecated, use TrackPaymentV2. TrackPayment returns an update stream for
+    the payment identified by the payment hash.
+    */
+    rpc TrackPayment (TrackPaymentRequest) returns (stream PaymentStatus) {
+        option deprecated = true;
+    }
+
+    /**
+    HtlcInterceptor dispatches a bi-directional streaming RPC in which
+    Forwarded HTLC requests are sent to the client and the client responds with
+    a boolean that tells LND if this htlc should be intercepted.
+    In case of interception, the htlc can be either settled, cancelled or
+    resumed later by using the ResolveHoldForward endpoint.
+    */
+    rpc HtlcInterceptor (stream ForwardHtlcInterceptResponse)
+        returns (stream ForwardHtlcInterceptRequest);
+
+    /* lncli: `updatechanstatus`
+    UpdateChanStatus attempts to manually set the state of a channel
+    (enabled, disabled, or auto). A manual "disable" request will cause the
+    channel to stay disabled until a subsequent manual request of either
+    "enable" or "auto".
+    */
+    rpc UpdateChanStatus (UpdateChanStatusRequest)
+        returns (UpdateChanStatusResponse);
+}
+
+message SendPaymentRequest {
+    // The identity pubkey of the payment recipient
+    bytes dest = 1;
+
+    /*
+    Number of satoshis to send.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt = 2;
+
+    // The hash to use within the payment's HTLC
+    bytes payment_hash = 3;
+
+    /*
+    The CLTV delta from the current height that should be used to set the
+    timelock for the final hop.
+    */
+    int32 final_cltv_delta = 4;
+
+    /*
+    A bare-bones invoice for a payment within the Lightning Network.  With the
+    details of the invoice, the sender has all the data necessary to send a
+    payment to the recipient. The amount in the payment request may be zero. In
+    that case it is required to set the amt field as well. If no payment request
+    is specified, the following fields are required: dest, amt and payment_hash.
+    */
+    string payment_request = 5;
+
+    /*
+    An upper limit on the amount of time we should spend when attempting to
+    fulfill the payment. This is expressed in seconds. If we cannot make a
+    successful payment within this time frame, an error will be returned.
+    This field must be non-zero.
+    */
+    int32 timeout_seconds = 6;
+
+    /*
+    The maximum number of satoshis that will be paid as a fee of the payment.
+    If this field is left to the default value of 0, only zero-fee routes will
+    be considered. This usually means single hop routes connecting directly to
+    the destination. To send the payment without a fee limit, use max int here.
+
+    The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
+    */
+    int64 fee_limit_sat = 7;
+
+    /*
+    Deprecated, use outgoing_chan_ids. The channel id of the channel that must
+    be taken to the first hop. If zero, any channel may be used (unless
+    outgoing_chan_ids are set).
+    */
+    uint64 outgoing_chan_id = 8 [jstype = JS_STRING, deprecated = true];
+
+    /*
+    An optional maximum total time lock for the route. This should not
+    exceed lnd's `--max-cltv-expiry` setting. If zero, then the value of
+    `--max-cltv-expiry` is enforced.
+    */
+    int32 cltv_limit = 9;
+
+    /*
+    Optional route hints to reach the destination through private channels.
+    */
+    repeated lnrpc.RouteHint route_hints = 10;
+
+    /*
+    An optional field that can be used to pass an arbitrary set of TLV records
+    to a peer which understands the new records. This can be used to pass
+    application specific data during the payment attempt. Record types are
+    required to be in the custom range >= 65536. When using REST, the values
+    must be encoded as base64.
+    */
+    map<uint64, bytes> dest_custom_records = 11;
+
+    /*
+    Number of millisatoshis to send.
+
+    The fields amt and amt_msat are mutually exclusive.
+    */
+    int64 amt_msat = 12;
+
+    /*
+    The maximum number of millisatoshis that will be paid as a fee of the
+    payment. If this field is left to the default value of 0, only zero-fee
+    routes will be considered. This usually means single hop routes connecting
+    directly to the destination. To send the payment without a fee limit, use
+    max int here.
+
+    The fields fee_limit_sat and fee_limit_msat are mutually exclusive.
+    */
+    int64 fee_limit_msat = 13;
+
+    /*
+    The pubkey of the last hop of the route. If empty, any hop may be used.
+    */
+    bytes last_hop_pubkey = 14;
+
+    // If set, circular payments to self are permitted.
+    bool allow_self_payment = 15;
+
+    /*
+    Features assumed to be supported by the final node. All transitive feature
+    dependencies must also be set properly. For a given feature bit pair, either
+    optional or remote may be set, but not both. If this field is nil or empty,
+    the router will try to load destination features from the graph as a
+    fallback.
+    */
+    repeated lnrpc.FeatureBit dest_features = 16;
+
+    /*
+    The maximum number of partial payments that may be use to complete the full
+    amount.
+    */
+    uint32 max_parts = 17;
+
+    /*
+    If set, only the final payment update is streamed back. Intermediate updates
+    that show which htlcs are still in flight are suppressed.
+    */
+    bool no_inflight_updates = 18;
+
+    /*
+    The channel ids of the channels are allowed for the first hop. If empty,
+    any channel may be used.
+    */
+    repeated uint64 outgoing_chan_ids = 19;
+
+    /*
+    An optional payment addr to be included within the last hop of the route.
+    This is also called payment secret in specifications (e.g. BOLT 11).
+    */
+    bytes payment_addr = 20;
+
+    /*
+    The largest payment split that should be attempted when making a payment if
+    splitting is necessary. Setting this value will effectively cause lnd to
+    split more aggressively, vs only when it thinks it needs to. Note that this
+    value is in milli-satoshis.
+    */
+    uint64 max_shard_size_msat = 21;
+
+    /*
+    If set, an AMP-payment will be attempted.
+    */
+    bool amp = 22;
+
+    /*
+    The time preference for this payment. Set to -1 to optimize for fees
+    only, to 1 to optimize for reliability only or a value inbetween for a mix.
+    */
+    double time_pref = 23;
+
+    /*
+    If set, the payment loop can be interrupted by manually canceling the
+    payment context, even before the payment timeout is reached. Note that the
+    payment may still succeed after cancellation, as in-flight attempts can
+    still settle afterwards. Canceling will only prevent further attempts from
+    being sent.
+    */
+    bool cancelable = 24;
+}
+
+message TrackPaymentRequest {
+    // The hash of the payment to look up.
+    bytes payment_hash = 1;
+
+    /*
+    If set, only the final payment update is streamed back. Intermediate updates
+    that show which htlcs are still in flight are suppressed.
+    */
+    bool no_inflight_updates = 2;
+}
+
+message TrackPaymentsRequest {
+    /*
+    If set, only the final payment updates are streamed back. Intermediate
+    updates that show which htlcs are still in flight are suppressed.
+    */
+    bool no_inflight_updates = 1;
+}
+
+message RouteFeeRequest {
+    /*
+    The destination one wishes to obtain a routing fee quote to. If set, this
+    parameter requires the amt_sat parameter also to be set. This parameter
+    combination triggers a graph based routing fee estimation as opposed to a
+    payment probe based estimate in case a payment request is provided. The
+    graph based estimation is an algorithm that is executed on the in memory
+    graph. Hence its runtime is significantly shorter than a payment probe
+    estimation that sends out actual payments to the network.
+    */
+    bytes dest = 1;
+
+    /*
+    The amount one wishes to send to the target destination. It is only to be
+    used in combination with the dest parameter.
+    */
+    int64 amt_sat = 2;
+
+    /*
+    A payment request of the target node that the route fee request is intended
+    for. Its parameters are input to probe payments that estimate routing fees.
+    The timeout parameter can be specified to set a maximum time on the probing
+    attempt. Cannot be used in combination with dest and amt_sat.
+    */
+    string payment_request = 3;
+
+    /*
+    A user preference of how long a probe payment should maximally be allowed to
+    take, denoted in seconds. The probing payment loop is aborted if this
+    timeout is reached. Note that the probing process itself can take longer
+    than the timeout if the HTLC becomes delayed or stuck. Canceling the context
+    of this call will not cancel the payment loop, the duration is only
+    controlled by the timeout parameter.
+    */
+    uint32 timeout = 4;
+}
+
+message RouteFeeResponse {
+    /*
+    A lower bound of the estimated fee to the target destination within the
+    network, expressed in milli-satoshis.
+    */
+    int64 routing_fee_msat = 1;
+
+    /*
+    An estimate of the worst case time delay that can occur. Note that callers
+    will still need to factor in the final CLTV delta of the last hop into this
+    value.
+    */
+    int64 time_lock_delay = 2;
+
+    /*
+    An indication whether a probing payment succeeded or whether and why it
+    failed. FAILURE_REASON_NONE indicates success.
+    */
+    lnrpc.PaymentFailureReason failure_reason = 5;
+}
+
+message SendToRouteRequest {
+    // The payment hash to use for the HTLC.
+    bytes payment_hash = 1;
+
+    // Route that should be used to attempt to complete the payment.
+    lnrpc.Route route = 2;
+
+    /*
+    Whether the payment should be marked as failed when a temporary error is
+    returned from the given route. Set it to true so the payment won't be
+    failed unless a terminal error is occurred, such as payment timeout, no
+    routes, incorrect payment details, or insufficient funds.
+    */
+    bool skip_temp_err = 3;
+}
+
+message SendToRouteResponse {
+    // The preimage obtained by making the payment.
+    bytes preimage = 1;
+
+    // The failure message in case the payment failed.
+    lnrpc.Failure failure = 2;
+}
+
+message ResetMissionControlRequest {
+}
+
+message ResetMissionControlResponse {
+}
+
+message QueryMissionControlRequest {
+}
+
+// QueryMissionControlResponse contains mission control state.
+message QueryMissionControlResponse {
+    reserved 1;
+
+    // Node pair-level mission control state.
+    repeated PairHistory pairs = 2;
+}
+
+message XImportMissionControlRequest {
+    // Node pair-level mission control state to be imported.
+    repeated PairHistory pairs = 1;
+
+    // Whether to force override MC pair history. Note that even with force
+    // override the failure pair is imported before the success pair and both
+    // still clamp existing failure/success amounts.
+    bool force = 2;
+}
+
+message XImportMissionControlResponse {
+}
+
+// PairHistory contains the mission control state for a particular node pair.
+message PairHistory {
+    // The source node pubkey of the pair.
+    bytes node_from = 1;
+
+    // The destination node pubkey of the pair.
+    bytes node_to = 2;
+
+    reserved 3, 4, 5, 6;
+
+    PairData history = 7;
+}
+
+message PairData {
+    // Time of last failure.
+    int64 fail_time = 1;
+
+    /*
+    Lowest amount that failed to forward rounded to whole sats. This may be
+    set to zero if the failure is independent of amount.
+    */
+    int64 fail_amt_sat = 2;
+
+    /*
+    Lowest amount that failed to forward in millisats. This may be
+    set to zero if the failure is independent of amount.
+    */
+    int64 fail_amt_msat = 4;
+
+    reserved 3;
+
+    // Time of last success.
+    int64 success_time = 5;
+
+    // Highest amount that we could successfully forward rounded to whole sats.
+    int64 success_amt_sat = 6;
+
+    // Highest amount that we could successfully forward in millisats.
+    int64 success_amt_msat = 7;
+}
+
+message GetMissionControlConfigRequest {
+}
+
+message GetMissionControlConfigResponse {
+    /*
+    Mission control's currently active config.
+    */
+    MissionControlConfig config = 1;
+}
+
+message SetMissionControlConfigRequest {
+    /*
+    The config to set for mission control. Note that all values *must* be set,
+    because the full config will be applied.
+    */
+    MissionControlConfig config = 1;
+}
+
+message SetMissionControlConfigResponse {
+}
+
+message MissionControlConfig {
+    /*
+    Deprecated, use AprioriParameters. The amount of time mission control will
+    take to restore a penalized node or channel back to 50% success probability,
+    expressed in seconds. Setting this value to a higher value will penalize
+    failures for longer, making mission control less likely to route through
+    nodes and channels that we have previously recorded failures for.
+    */
+    uint64 half_life_seconds = 1 [deprecated = true];
+
+    /*
+    Deprecated, use AprioriParameters. The probability of success mission
+    control should assign to hop in a route where it has no other information
+    available. Higher values will make mission control more willing to try hops
+    that we have no information about, lower values will discourage trying these
+    hops.
+    */
+    float hop_probability = 2 [deprecated = true];
+
+    /*
+    Deprecated, use AprioriParameters. The importance that mission control
+    should place on historical results, expressed as a value in [0;1]. Setting
+    this value to 1 will ignore all historical payments and just use the hop
+    probability to assess the probability of success for each hop. A zero value
+    ignores hop probability completely and relies entirely on historical
+    results, unless none are available.
+    */
+    float weight = 3 [deprecated = true];
+
+    /*
+    The maximum number of payment results that mission control will store.
+    */
+    uint32 maximum_payment_results = 4;
+
+    /*
+    The minimum time that must have passed since the previously recorded failure
+    before we raise the failure amount.
+    */
+    uint64 minimum_failure_relax_interval = 5;
+
+    enum ProbabilityModel {
+        APRIORI = 0;
+        BIMODAL = 1;
+    }
+
+    /*
+    ProbabilityModel defines which probability estimator should be used in
+    pathfinding. Note that the bimodal estimator is experimental.
+    */
+    ProbabilityModel model = 6;
+
+    /*
+    EstimatorConfig is populated dependent on the estimator type.
+    */
+    oneof EstimatorConfig {
+        AprioriParameters apriori = 7;
+        BimodalParameters bimodal = 8;
+    }
+}
+
+message BimodalParameters {
+    /*
+    NodeWeight defines how strongly other previous forwardings on channels of a
+    router should be taken into account when computing a channel's probability
+    to route. The allowed values are in the range [0, 1], where a value of 0
+    means that only direct information about a channel is taken into account.
+    */
+    double node_weight = 1;
+
+    /*
+    ScaleMsat describes the scale over which channels statistically have some
+    liquidity left. The value determines how quickly the bimodal distribution
+    drops off from the edges of a channel. A larger value (compared to typical
+    channel capacities) means that the drop off is slow and that channel
+    balances are distributed more uniformly. A small value leads to the
+    assumption of very unbalanced channels.
+    */
+    uint64 scale_msat = 2;
+
+    /*
+    DecayTime describes the information decay of knowledge about previous
+    successes and failures in channels. The smaller the decay time, the quicker
+    we forget about past forwardings.
+    */
+    uint64 decay_time = 3;
+}
+
+message AprioriParameters {
+    /*
+    The amount of time mission control will take to restore a penalized node
+    or channel back to 50% success probability, expressed in seconds. Setting
+    this value to a higher value will penalize failures for longer, making
+    mission control less likely to route through nodes and channels that we
+    have previously recorded failures for.
+    */
+    uint64 half_life_seconds = 1;
+
+    /*
+    The probability of success mission control should assign to hop in a route
+    where it has no other information available. Higher values will make mission
+    control more willing to try hops that we have no information about, lower
+    values will discourage trying these hops.
+    */
+    double hop_probability = 2;
+
+    /*
+    The importance that mission control should place on historical results,
+    expressed as a value in [0;1]. Setting this value to 1 will ignore all
+    historical payments and just use the hop probability to assess the
+    probability of success for each hop. A zero value ignores hop probability
+    completely and relies entirely on historical results, unless none are
+    available.
+    */
+    double weight = 3;
+
+    /*
+    The fraction of a channel's capacity that we consider to have liquidity. For
+    amounts that come close to or exceed the fraction, an additional penalty is
+    applied. A value of 1.0 disables the capacity factor. Allowed values are in
+    [0.75, 1.0].
+    */
+    double capacity_fraction = 4;
+}
+
+message QueryProbabilityRequest {
+    // The source node pubkey of the pair.
+    bytes from_node = 1;
+
+    // The destination node pubkey of the pair.
+    bytes to_node = 2;
+
+    // The amount for which to calculate a probability.
+    int64 amt_msat = 3;
+}
+
+message QueryProbabilityResponse {
+    // The success probability for the requested pair.
+    double probability = 1;
+
+    // The historical data for the requested pair.
+    PairData history = 2;
+}
+
+message BuildRouteRequest {
+    /*
+    The amount to send expressed in msat. If set to zero, the minimum routable
+    amount is used.
+    */
+    int64 amt_msat = 1;
+
+    /*
+    CLTV delta from the current height that should be used for the timelock
+    of the final hop
+    */
+    int32 final_cltv_delta = 2;
+
+    /*
+    The channel id of the channel that must be taken to the first hop. If zero,
+    any channel may be used.
+    */
+    uint64 outgoing_chan_id = 3 [jstype = JS_STRING];
+
+    /*
+    A list of hops that defines the route. This does not include the source hop
+    pubkey.
+    */
+    repeated bytes hop_pubkeys = 4;
+
+    /*
+    An optional payment addr to be included within the last hop of the route.
+    This is also called payment secret in specifications (e.g. BOLT 11).
+    */
+    bytes payment_addr = 5;
+}
+
+message BuildRouteResponse {
+    /*
+    Fully specified route that can be used to execute the payment.
+    */
+    lnrpc.Route route = 1;
+}
+
+message SubscribeHtlcEventsRequest {
+}
+
+/*
+HtlcEvent contains the htlc event that was processed. These are served on a
+best-effort basis; events are not persisted, delivery is not guaranteed
+(in the event of a crash in the switch, forward events may be lost) and
+some events may be replayed upon restart. Events consumed from this package
+should be de-duplicated by the htlc's unique combination of incoming and
+outgoing channel id and htlc id. [EXPERIMENTAL]
+*/
+message HtlcEvent {
+    /*
+    The short channel id that the incoming htlc arrived at our node on. This
+    value is zero for sends.
+    */
+    uint64 incoming_channel_id = 1;
+
+    /*
+    The short channel id that the outgoing htlc left our node on. This value
+    is zero for receives.
+    */
+    uint64 outgoing_channel_id = 2;
+
+    /*
+    Incoming id is the index of the incoming htlc in the incoming channel.
+    This value is zero for sends.
+    */
+    uint64 incoming_htlc_id = 3;
+
+    /*
+    Outgoing id is the index of the outgoing htlc in the outgoing channel.
+    This value is zero for receives.
+    */
+    uint64 outgoing_htlc_id = 4;
+
+    /*
+    The time in unix nanoseconds that the event occurred.
+    */
+    uint64 timestamp_ns = 5;
+
+    enum EventType {
+        UNKNOWN = 0;
+        SEND = 1;
+        RECEIVE = 2;
+        FORWARD = 3;
+    }
+
+    /*
+    The event type indicates whether the htlc was part of a send, receive or
+    forward.
+    */
+    EventType event_type = 6;
+
+    oneof event {
+        ForwardEvent forward_event = 7;
+        ForwardFailEvent forward_fail_event = 8;
+        SettleEvent settle_event = 9;
+        LinkFailEvent link_fail_event = 10;
+        SubscribedEvent subscribed_event = 11;
+        FinalHtlcEvent final_htlc_event = 12;
+    }
+}
+
+message HtlcInfo {
+    // The timelock on the incoming htlc.
+    uint32 incoming_timelock = 1;
+
+    // The timelock on the outgoing htlc.
+    uint32 outgoing_timelock = 2;
+
+    // The amount of the incoming htlc.
+    uint64 incoming_amt_msat = 3;
+
+    // The amount of the outgoing htlc.
+    uint64 outgoing_amt_msat = 4;
+}
+
+message ForwardEvent {
+    // Info contains details about the htlc that was forwarded.
+    HtlcInfo info = 1;
+}
+
+message ForwardFailEvent {
+}
+
+message SettleEvent {
+    // The revealed preimage.
+    bytes preimage = 1;
+}
+
+message FinalHtlcEvent {
+    bool settled = 1;
+    bool offchain = 2;
+}
+
+message SubscribedEvent {
+}
+
+message LinkFailEvent {
+    // Info contains details about the htlc that we failed.
+    HtlcInfo info = 1;
+
+    // FailureCode is the BOLT error code for the failure.
+    lnrpc.Failure.FailureCode wire_failure = 2;
+
+    /*
+    FailureDetail provides additional information about the reason for the
+    failure. This detail enriches the information provided by the wire message
+    and may be 'no detail' if the wire message requires no additional metadata.
+    */
+    FailureDetail failure_detail = 3;
+
+    // A string representation of the link failure.
+    string failure_string = 4;
+}
+
+enum FailureDetail {
+    UNKNOWN = 0;
+    NO_DETAIL = 1;
+    ONION_DECODE = 2;
+    LINK_NOT_ELIGIBLE = 3;
+    ON_CHAIN_TIMEOUT = 4;
+    HTLC_EXCEEDS_MAX = 5;
+    INSUFFICIENT_BALANCE = 6;
+    INCOMPLETE_FORWARD = 7;
+    HTLC_ADD_FAILED = 8;
+    FORWARDS_DISABLED = 9;
+    INVOICE_CANCELED = 10;
+    INVOICE_UNDERPAID = 11;
+    INVOICE_EXPIRY_TOO_SOON = 12;
+    INVOICE_NOT_OPEN = 13;
+    MPP_INVOICE_TIMEOUT = 14;
+    ADDRESS_MISMATCH = 15;
+    SET_TOTAL_MISMATCH = 16;
+    SET_TOTAL_TOO_LOW = 17;
+    SET_OVERPAID = 18;
+    UNKNOWN_INVOICE = 19;
+    INVALID_KEYSEND = 20;
+    MPP_IN_PROGRESS = 21;
+    CIRCULAR_ROUTE = 22;
+}
+
+enum PaymentState {
+    /*
+    Payment is still in flight.
+    */
+    IN_FLIGHT = 0;
+
+    /*
+    Payment completed successfully.
+    */
+    SUCCEEDED = 1;
+
+    /*
+    There are more routes to try, but the payment timeout was exceeded.
+    */
+    FAILED_TIMEOUT = 2;
+
+    /*
+    All possible routes were tried and failed permanently. Or were no
+    routes to the destination at all.
+    */
+    FAILED_NO_ROUTE = 3;
+
+    /*
+    A non-recoverable error has occurred.
+    */
+    FAILED_ERROR = 4;
+
+    /*
+    Payment details incorrect (unknown hash, invalid amt or
+    invalid final cltv delta)
+    */
+    FAILED_INCORRECT_PAYMENT_DETAILS = 5;
+
+    /*
+    Insufficient local balance.
+    */
+    FAILED_INSUFFICIENT_BALANCE = 6;
+}
+
+message PaymentStatus {
+    // Current state the payment is in.
+    PaymentState state = 1;
+
+    /*
+    The pre-image of the payment when state is SUCCEEDED.
+    */
+    bytes preimage = 2;
+
+    reserved 3;
+
+    /*
+    The HTLCs made in attempt to settle the payment [EXPERIMENTAL].
+    */
+    repeated lnrpc.HTLCAttempt htlcs = 4;
+}
+
+message CircuitKey {
+    /// The id of the channel that the is part of this circuit.
+    uint64 chan_id = 1;
+
+    /// The index of the incoming htlc in the incoming channel.
+    uint64 htlc_id = 2;
+}
+
+message ForwardHtlcInterceptRequest {
+    /*
+    The key of this forwarded htlc. It defines the incoming channel id and
+    the index in this channel.
+    */
+    CircuitKey incoming_circuit_key = 1;
+
+    // The incoming htlc amount.
+    uint64 incoming_amount_msat = 5;
+
+    // The incoming htlc expiry.
+    uint32 incoming_expiry = 6;
+
+    /*
+    The htlc payment hash. This value is not guaranteed to be unique per
+    request.
+    */
+    bytes payment_hash = 2;
+
+    // The requested outgoing channel id for this forwarded htlc. Because of
+    // non-strict forwarding, this isn't necessarily the channel over which the
+    // packet will be forwarded eventually. A different channel to the same peer
+    // may be selected as well.
+    uint64 outgoing_requested_chan_id = 7;
+
+    // The outgoing htlc amount.
+    uint64 outgoing_amount_msat = 3;
+
+    // The outgoing htlc expiry.
+    uint32 outgoing_expiry = 4;
+
+    // Any custom records that were present in the payload.
+    map<uint64, bytes> custom_records = 8;
+
+    // The onion blob for the next hop
+    bytes onion_blob = 9;
+
+    // The block height at which this htlc will be auto-failed to prevent the
+    // channel from force-closing.
+    int32 auto_fail_height = 10;
+}
+
+/**
+ForwardHtlcInterceptResponse enables the caller to resolve a previously hold
+forward. The caller can choose either to:
+- `Resume`: Execute the default behavior (usually forward).
+- `Reject`: Fail the htlc backwards.
+- `Settle`: Settle this htlc with a given preimage.
+*/
+message ForwardHtlcInterceptResponse {
+    /**
+    The key of this forwarded htlc. It defines the incoming channel id and
+    the index in this channel.
+    */
+    CircuitKey incoming_circuit_key = 1;
+
+    // The resolve action for this intercepted htlc.
+    ResolveHoldForwardAction action = 2;
+
+    // The preimage in case the resolve action is Settle.
+    bytes preimage = 3;
+
+    // Encrypted failure message in case the resolve action is Fail.
+    //
+    // If failure_message is specified, the failure_code field must be set
+    // to zero.
+    bytes failure_message = 4;
+
+    // Return the specified failure code in case the resolve action is Fail. The
+    // message data fields are populated automatically.
+    //
+    // If a non-zero failure_code is specified, failure_message must not be set.
+    //
+    // For backwards-compatibility reasons, TEMPORARY_CHANNEL_FAILURE is the
+    // default value for this field.
+    lnrpc.Failure.FailureCode failure_code = 5;
+}
+
+enum ResolveHoldForwardAction {
+    SETTLE = 0;
+    FAIL = 1;
+    RESUME = 2;
+}
+
+message UpdateChanStatusRequest {
+    lnrpc.ChannelPoint chan_point = 1;
+
+    ChanStatusAction action = 2;
+}
+
+enum ChanStatusAction {
+    ENABLE = 0;
+    DISABLE = 1;
+    AUTO = 2;
+}
+
+message UpdateChanStatusResponse {
+}

+ 2 - 1
crates/cdk-mint-rpc/Cargo.toml

@@ -24,7 +24,7 @@ cdk = { workspace = true, features = [
     "mint",
 ] }
 clap.workspace = true
-tonic.workspace = true
+tonic = { workspace = true, features = ["transport"] }
 tracing.workspace = true
 tracing-subscriber.workspace = true
 tokio.workspace = true
@@ -33,6 +33,7 @@ serde.workspace = true
 thiserror.workspace = true
 prost.workspace = true
 home.workspace = true
+rustls.workspace = true
 
 
 [build-dependencies]

+ 4 - 0
crates/cdk-mint-rpc/src/bin/mint_rpc_cli.rs

@@ -94,6 +94,10 @@ async fn main() -> Result<()> {
     tracing::debug!("Using work dir: {}", work_dir.display());
 
     let channel = if work_dir.join("tls").is_dir() {
+        if rustls::crypto::CryptoProvider::get_default().is_none() {
+            let _ = rustls::crypto::ring::default_provider().install_default();
+        }
+
         // TLS directory exists, configure TLS
         let server_root_ca_cert = std::fs::read_to_string(work_dir.join("tls/ca.pem")).unwrap();
         let server_root_ca_cert = Certificate::from_pem(server_root_ca_cert);

+ 1 - 1
crates/cdk-payment-processor/Cargo.toml

@@ -39,7 +39,7 @@ utoipa = { workspace = true, optional = true }
 futures.workspace = true
 serde_json.workspace = true
 serde_with.workspace = true
-tonic.workspace = true
+tonic = { workspace = true, features = ["router"] }
 prost.workspace = true
 tokio-stream.workspace = true
 tokio-util = { workspace = true, default-features = false }

+ 1 - 1
crates/cdk-signatory/Cargo.toml

@@ -22,7 +22,7 @@ cdk-common = { workspace = true, default-features = false, features = [
     "mint",
     "auth",
 ] }
-tonic = { workspace = true, optional = true }
+tonic = { workspace = true, optional = true, features = ["router"] }
 prost = { workspace = true, optional = true }
 tracing.workspace = true
 

+ 2 - 1
crates/cdk/Cargo.toml

@@ -12,7 +12,7 @@ license.workspace = true
 
 [features]
 default = ["mint", "wallet", "auth"]
-wallet = ["dep:reqwest", "cdk-common/wallet"]
+wallet = ["dep:reqwest", "cdk-common/wallet", "dep:rustls"]
 mint = ["dep:futures", "dep:reqwest", "cdk-common/mint", "cdk-signatory"]
 auth = ["dep:jsonwebtoken", "cdk-common/auth", "cdk-common/auth"]
 # We do not commit to a MSRV with swagger enabled
@@ -61,6 +61,7 @@ tokio-tungstenite = { workspace = true, features = [
     "rustls-tls-native-roots",
     "connect"
 ] }
+rustls = { workspace = true, optional = true }
 
 [target.'cfg(target_arch = "wasm32")'.dependencies]
 tokio = { workspace = true, features = ["rt", "macros", "sync", "time"] }

+ 5 - 0
crates/cdk/src/wallet/mint_connector/http_client.rs

@@ -34,6 +34,11 @@ struct HttpClientCore {
 
 impl HttpClientCore {
     fn new() -> Self {
+        #[cfg(not(target_arch = "wasm32"))]
+        if rustls::crypto::CryptoProvider::get_default().is_none() {
+            let _ = rustls::crypto::ring::default_provider().install_default();
+        }
+
         Self {
             inner: Client::new(),
         }