Skip to content

core lightning #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Mar 19, 2025
Merged

core lightning #4

merged 15 commits into from
Mar 19, 2025

Conversation

ntheile
Copy link
Contributor

@ntheile ntheile commented Mar 5, 2025

https://docs.corelightning.org/docs/rest

Summary by CodeRabbit

  • New Features

    • Extended Lightning Network integration now supports enhanced node interactions, streamlined payment processing, and richer transaction details (including payer notes, external IDs, and payment hashes) for a more robust experience.
    • Introduced new interfaces and methods for invoice creation, offer retrieval, and transaction listing, enhancing user capabilities.
    • A new module for Core Lightning Node (CLN) has been added, providing additional functionalities for interacting with the CLN API.
    • Added support for new configuration options and environment variables to facilitate improved setup and testing.
  • Bug Fixes

    • Improved handling of optional parameters in invoice creation and transaction listing, ensuring more flexible and error-free operations.
  • Documentation

    • Updated setup and troubleshooting instructions, refined environment variable configurations, and added a visual sequence diagram to clarify system interactions for smoother integration and better user guidance.
    • New environment variables added for improved configuration and testing.
  • Chores

    • Removed deprecated database functionality to streamline the codebase and reduce complexity.

Copy link

coderabbitai bot commented Mar 5, 2025

Walkthrough

The changes refactor the Lightning Network integrations by removing several obsolete interfaces and classes while introducing a new CLN implementation. A new class and related modules for ClnNode have been added, with corresponding API functions, types, and tests to handle node information, invoice payments, and transaction listings. The exports in both the Node.js bindings and Rust library have been updated, and documentation, including environment variables and sequence diagrams, has been revised accordingly.

Changes

File/Module Change Summary
bindings/lni_nodejs/index.d.ts Removed multiple interfaces and the Db class; modified PhoenixdNode (methods removed); added new class ClnNode with an updated payOffer signature.
bindings/lni_nodejs/src/lib.rs Updated exports by adding new types (e.g., Transaction, InvoiceType, ListTransactionsParams, PayInvoiceResponse) and ClnNode; removed export for Db.
bindings/lni_uniffi/src/lni.udl Added new optional fields (payer_note, external_id) to Transaction; added payment_hash to PayInvoiceResponse; replaced several fields in ListTransactionsParams.
crates/lni/cln/api.rs Introduced new API functions (get_info, pay_offer, lookup_invoice, list_transactions) and a helper function for the CLN Lightning API.
crates/lni/cln/lib.rs Added new modules with ClnConfig and ClnNode structs along with methods (constructor, async API calls) and tests for CLN interactions.
crates/lni/cln/types.rs Introduced new types including InfoResponse, FetchInvoiceResponse, PayResponse, PaidOutpoint, Invoice, and InvoicesResponse for serializing/deserializing API data.
crates/lni/lib.rs Introduced a new module cln (with sub-modules: lib, api, types) and updated the existing phoenixd module exports (removed ListTransactionsParams).
crates/lni/phoenixd/api.rs Removed several invoice/payment response structs; updated invoice creation and lookup logic to include new fields (payer_note, external_id).
crates/lni/types.rs Updated Transaction to include optional payer_note and external_id; updated PayInvoiceResponse with a mandatory payment_hash; added new struct ListTransactionsParams.
readme.md Revised documentation and troubleshooting steps; updated environment variable names and build commands; added a sequence diagram and a new "To Research" item.
bindings/lni_nodejs/index.js Removed imports and exports for InvoiceType and Db; added ClnNode to the native binding exports.
bindings/lni_nodejs/main.mjs Encapsulated logic into two async functions, phoenixd() and new cln(), and updated environment variable references in accordance with the new node implementations.
bindings/lni_nodejs/src/phoenixd.rs Updated the list_transactions method signature to use the new ListTransactionsParams and simplified parameter handling.
bindings/lni_uniffi/src/lib.rs Adjusted public imports: removed specific imports from lni::phoenixd and added a new import for the lni::cln module.
crates/lni/phoenixd/types.rs Added a new file defining structs (InfoResponse, Bolt11Req, InvoiceResponse, OutgoingPaymentResponse, PayResponse) for invoice and payment processing.
bindings/lni_react_native/ (App.tsx, build.sh, package.json, ubrn.config.yaml) In React Native bindings: renamed constants and updated transaction parameters; removed a cleanup command in the build script; updated dependency versions and branch configuration.

Sequence Diagram(s)

sequenceDiagram
    participant Main as main()
    participant Phoenixd as PhoenixdNode API
    participant Cln as ClnNode API
    participant LN as Lightning API

    Main->>Phoenixd: Call phoenixd() function
    Phoenixd->>LN: Fetch node info / process payment offer
    LN-->>Phoenixd: Return invoice/payment response
    Phoenixd->>Main: Return results

    Main->>Cln: Call cln() function
    Cln->>LN: Fetch node info / lookup invoice / process pay offer
    LN-->>Cln: Return transaction/payment details
    Cln->>Main: Return results
Loading

Poem

I'm a hopping rabbit, coding all day,
Leaping over old code in my playful way.
ClnNode springs to life with a cheerful glow,
While Phoenixd steps aside, letting new features show.
I nibble on APIs, transactions, and more,
Celebrating these changes—hoppy to the core! 🐇🌟

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33adcfc and bacbaf4.

📒 Files selected for processing (1)
  • bindings/lni_uniffi/uniffi.toml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • bindings/lni_uniffi/uniffi.toml

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (2)
crates/lni/phoenixd/api.rs (2)

96-114: ⚠️ Potential issue

Improve error handling in get_info function.

The function has several calls to unwrap() which can lead to panics if the network request fails or returns malformed data. Consider proper error handling with the ? operator or pattern matching.

-    let response_text = response.unwrap().text().unwrap();
+    let response = response.map_err(|e| ApiError::Network { reason: e.to_string() })?;
+    let response_text = response.text().map_err(|e| ApiError::Network { reason: e.to_string() })?;

This pattern should be applied throughout the file for robust error handling.


220-223: 🛠️ Refactor suggestion

Improve error handling in pay_resp deserialization.

The error handling for JSON deserialization returns the entire response text as the error reason, which could expose sensitive information. Consider returning a more generic error message.

-        Err(e) => return Err(ApiError::Json { reason: response_text.to_string() }),
+        Err(e) => return Err(ApiError::Json { reason: format!("Failed to parse payment response: {}", e) }),
🧹 Nitpick comments (14)
bindings/lni_nodejs/src/lib.rs (1)

10-10: Remove redundant explicit import

There's already a wildcard import pub use lni::types::*; on line 9 that would import Transaction along with all other types from this module. The additional explicit import is unnecessary and could cause confusion.

pub use lni::types::*;
-pub use lni::types::{Transaction};
crates/lni/cln/types.rs (1)

3-12: Add additional derive traits and documentation

The InfoResponse struct could benefit from additional derive traits commonly used for data structures, such as Clone, PartialEq, and possibly Serialize if needed. Additionally, consider adding documentation comments to explain the purpose of this struct and its fields.

use serde::Deserialize;
+use serde::Serialize;

-#[derive(Debug, Deserialize)]
+/// Response structure for CLN node information
+#[derive(Debug, Deserialize, Clone, PartialEq, Serialize)]
pub struct InfoResponse {
    // #[serde(rename = "nodeId")] // Handle JSON field `nodeId`
    // pub node_id: String,
+    /// The node's public key
    pub id: String,
+    /// The node's alias
    pub alias: String,
+    /// The node's color in hex format
    pub color: String,
+    /// The blockchain network (e.g., "bitcoin", "testnet")
    pub network: String,
+    /// Current block height known to the node
    pub blockheight: i64,
}
bindings/lni_uniffi/src/lni.udl (1)

87-101: Consider adding documentation for new fields

While the field additions are good, adding comments to describe the purpose of the new fields would improve clarity, similar to how documentation could be added to other dictionaries in the file.

dictionary Transaction {
    string type_;
    string invoice;
    string description;
    string description_hash;
    string preimage;
    string payment_hash;
    i64 amount_msats;
    i64 fees_paid;
    i64 created_at;
    i64 expires_at;
    i64 settled_at;
+    // Optional note provided by the payer
    string? payer_note;
+    // Optional external identifier for integration with other systems
    string? external_id;
};
crates/lni/types.rs (1)

175-175: Add the payment_hash field before preimage for consistency.

The payment_hash field is a logical addition to the PayInvoiceResponse struct. However, for better organization and consistency, consider placing it before the preimage field since the payment hash is typically derived first in the payment flow, and this ordering would match the fields in the Transaction struct.

@@ -174,8 +174,8 @@
 #[cfg_attr(feature = "napi_rs", napi(object))]
 #[derive(Debug, Serialize, Deserialize)]
 pub struct PayInvoiceResponse {
-    pub payment_hash: String,
     pub preimage: String,
+    pub payment_hash: String,
     pub fee: i64,
 }
crates/lni/cln/api.rs (1)

24-33: Populate the block_hash field from the response if available.

The block_hash field is currently hardcoded to an empty string, but it should be populated from the response if available.

     let node_info = NodeInfo {
         alias: info.alias,
         color: info.color,
         pubkey: info.id,
         network: info.network,
         block_height: info.blockheight,
-        block_hash: "".to_string(),
+        block_hash: info.block_hash.unwrap_or_default(),
     };
     Ok(node_info)

Note: You'll need to add a block_hash field to the InfoResponse struct in the types module.

readme.md (3)

118-127: Improve Markdown formatting for environment variables section.

The environment variables section has inconsistent formatting compared to other sections.

-### .env
-```
+### Environment Variables
+
+```env
 PHOENIXD_URL=http://localhost:9740
 PHOENIXD_PASSWORD=YOUR_HTTP_PASSWORD
 PHOENIXD_TEST_PAYMENT_HASH=YOUR_TEST_PAYMENT_HASH
 TEST_OFFER=lno***

 CLN_URL=http://localhost:3010
 CLN_RUNE=YOUR_RUNE
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


138-151: Good addition of native module instructions.

The instructions for using native modules in environments like Electron or Vercel are helpful. Consider standardizing the indentation and formatting to match the rest of the document.

-    - if you want to use the native node module (maybe for an electron app) you can reference the file `bindings/lni_nodejs/lni_js.${platform}-${arch}.node`. It would look something like in your project:
-        ```typescript
-        const path = require("path");
-        const os = require("os");
-        const platform = os.platform();
-        const arch = os.arch();
-        const nativeModulePath = path.join(
-        __dirname,
-        `../../code/lni/bindings/lni_nodejs/lni_js.${platform}-${arch}.node`
-        );
-        const { PhoenixdNode } = require(nativeModulePath);
-        ```
+    - If you want to use the native Node.js module (maybe for an Electron app), you can reference the file `bindings/lni_nodejs/lni_js.${platform}-${arch}.node`. 
+      
+      Example usage in your project:
+      
+      ```typescript
+      const path = require("path");
+      const os = require("os");
+      const platform = os.platform();
+      const arch = os.arch();
+      const nativeModulePath = path.join(
+        __dirname,
+        `../../code/lni/bindings/lni_nodejs/lni_js.${platform}-${arch}.node`
+      );
+      const { PhoenixdNode } = require(nativeModulePath);
+      ```
🧰 Tools
🪛 LanguageTool

[uncategorized] ~138-~138: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~138-~138: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


225-225: Format the URL properly in the research item.

The URL should be properly formatted as a link rather than a bare URL.

-- [ ] Facade REST API? - Use the same api as phoenixd https://phoenix.acinq.co/server/api as a facade in front of any lightning node implementation. 
+- [ ] Facade REST API? - Use the same API as phoenixd [https://phoenix.acinq.co/server/api](https://phoenix.acinq.co/server/api) as a facade in front of any lightning node implementation.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

225-225: Bare URL used
null

(MD034, no-bare-urls)

crates/lni/cln/lib.rs (3)

29-31: Avoid unnecessary cloning of strings.

The get_info method is unnecessarily cloning the URL and rune strings. Since these are just being passed to an API function, consider passing them by reference if the API supports it.

-    pub async fn get_info(&self) -> Result<NodeInfo, ApiError> {
-        crate::cln::api::get_info(self.url.clone(), self.rune.clone())
-    }
+    pub async fn get_info(&self) -> Result<NodeInfo, ApiError> {
+        crate::cln::api::get_info(self.url.as_str(), self.rune.as_str())
+    }

This would require modifying the signature of the get_info function in the api module to accept string slices (&str) instead of owned strings.


59-70: Fix error message in test function.

The error message in the test doesn't match the context. It mentions "Failed to get offer" but should be "Failed to get info" since you're testing the get_info method.

-                panic!("Failed to get offer: {:?}", e);
+                panic!("Failed to get info: {:?}", e);

34-71: Add more test coverage.

The test module only includes a positive test case for get_info. Consider adding tests for error scenarios, such as invalid URLs or authentication failures, to ensure robust error handling.

For example, you could add a test with an intentionally invalid URL:

#[test]
async fn test_get_info_invalid_url() {
    let node = ClnNode::new(ClnConfig {
        url: "invalid_url".to_string(),
        rune: RUNE.clone(),
    });
    
    match node.get_info().await {
        Ok(_) => {
            panic!("Expected an error but got a successful response");
        }
        Err(e) => {
            println!("Got expected error: {:?}", e);
            // Verify it's the right kind of error
        }
    }
}
crates/lni/phoenixd/api.rs (3)

130-136: Address TODO comments in bolt11_req.

There are TODO comments for the external_id and webhook_url fields. Since you've added support for these fields in the struct, consider implementing them properly.

-                external_id: None, // TODO
+                external_id: Some("".to_string()), // Initialize with empty string like other places

Would you like me to help implement these TODO items or create an issue to track them?


8-10: Track and address global TODO items.

There are TODO comments at the top of the file for list_channels and get_balance functions that haven't been implemented yet.

Would you like me to help implement these functions or create an issue to track them for future implementation?


101-103: Remove debugging println statement.

There's a println! statement that outputs the raw response. In production code, this should be replaced with proper logging or removed entirely.

-    println!("Raw response: {}", response_text);
+    // Use a proper logging framework instead of println
+    log::debug!("Raw response: {}", response_text);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dc1736 and 0207cbf.

⛔ Files ignored due to path filters (1)
  • bindings/lni_nodejs/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (10)
  • bindings/lni_nodejs/index.d.ts (2 hunks)
  • bindings/lni_nodejs/src/lib.rs (1 hunks)
  • bindings/lni_uniffi/src/lni.udl (2 hunks)
  • crates/lni/cln/api.rs (1 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/cln/types.rs (1 hunks)
  • crates/lni/lib.rs (1 hunks)
  • crates/lni/phoenixd/api.rs (8 hunks)
  • crates/lni/types.rs (2 hunks)
  • readme.md (3 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
readme.md

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


136-136: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


225-225: Bare URL used
null

(MD034, no-bare-urls)

🪛 LanguageTool
readme.md

[uncategorized] ~138-~138: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~138-~138: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🔇 Additional comments (19)
bindings/lni_uniffi/src/lni.udl (2)

99-100: LGTM - Good field additions to Transaction

The addition of optional fields payer_note and external_id to the Transaction dictionary is consistent with the field naming style in the file and appropriately marked as optional with string?.


199-199: LGTM - Good field addition to PayInvoiceResponse

The addition of the payment_hash field to the PayInvoiceResponse dictionary is consistent with the naming of other fields in the file.

bindings/lni_nodejs/index.d.ts (3)

62-63: LGTM - Proper TypeScript property additions

The added optional properties payerNote and externalId follow proper camelCase naming conventions for TypeScript/JavaScript and are correctly marked as optional with the ? suffix.


150-150: LGTM - Proper addition of paymentHash property

The addition of the paymentHash property to the PayInvoiceResponse interface follows proper camelCase naming convention for TypeScript/JavaScript.


181-181: Ensure API call is updated for the payerNote parameter

Line 181 shows the payOffer method already accepts an optional payerNote parameter, which aligns with the new field added to the Transaction interface. This is good consistency.

crates/lni/lib.rs (1)

29-33: Nice addition of a well-structured CLN module.

The new CLN module follows the same organizational pattern as the existing phoenixd module, with a clean separation of concerns into lib, api, and types submodules. This consistency makes the codebase more maintainable and easier to navigate.

crates/lni/types.rs (1)

46-47: Good addition of optional fields with clear documentation.

The new optional fields payer_note and external_id are well-documented with comments explaining their specific use cases for bolt12 and bolt11 respectively. Using Option<String> is appropriate for these fields that may not always be present.

crates/lni/cln/api.rs (1)

1-7: The imports and documentation look good.

Good job on including the link to Core Lightning API documentation in the comments. The imports are also well-organized, only importing what's needed.

readme.md (1)

135-135: Updated build command to use release mode.

The build command now correctly uses the --release flag, which is appropriate for generating optimized bindings for production use.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

crates/lni/cln/lib.rs (4)

9-19: Good struct definition with proper attributes for Node.js bindings.

The structure definitions look good with appropriate attributes for Node.js bindings. The #[cfg_attr(feature = "napi_rs", napi(object))] attribute ensures these structs are properly exposed to JavaScript when the feature is enabled.


21-27: Constructor implementation looks good.

The constructor for ClnNode is implemented correctly, creating a new instance from a ClnConfig object.


42-57: Good use of environment variables for test configuration.

The code uses dotenv and lazy_static to load and cache environment variables for testing, which is a good practice for handling test configuration without hardcoding sensitive information.


1-8:

❓ Verification inconclusive

Verify necessary imports and feature use.

The code defines conditional compilation for the napi_rs feature, which is common practice for creating bindings to other languages, specifically Node.js in this case. However, ensure that all the imports are being used and are necessary for the functionality.


🏁 Script executed:

#!/bin/bash
# Verify all imports are used

# Check if there are any unused imports in the file
rg -A 1 "use " crates/lni/cln/lib.rs | grep -v "#\[cfg" | grep "use"

Length of output: 307


Action Required: Verify All Import Usages

The file currently includes not only the conditional napi_rs import and the expected core imports but also additional ones (e.g., use super::*;, use dotenv::dotenv;, use lazy_static::lazy_static;, use std::env;, and use tokio::test;). Please ensure that every import declared is actually used or needed in this module. If some of them are only used for testing or were left over from earlier iterations, consider removing them to improve code clarity and reduce potential warnings.

crates/lni/phoenixd/api.rs (6)

54-57: Good field additions with helpful comments.

The addition of payer_note and external_id fields to the InvoiceResponse struct with comments explaining their purpose is well-implemented.


78-81: Consistent field additions across structs.

The addition of the same fields to OutgoingPaymentResponse maintains consistency across the API structures.


168-169: Properly initializing new fields in transaction creation.

The initialization of the new fields with empty strings wrapped in Some is appropriate. This ensures that the fields are always present in the returned Transaction struct.

Also applies to: 192-193


225-225: Important field addition to PayInvoiceResponse.

Adding the payment_hash field to the PayInvoiceResponse struct is an important improvement for tracking payments.


255-256: Good handling of optional fields in lookup_invoice.

Properly extracting the optional fields from InvoiceResponse with appropriate fallbacks to empty strings.


377-380:

❓ Verification inconclusive

Similar description behavior change for outgoing transactions.

Same issue as above - the description field is set to an empty string for outgoing transactions as well. Ensure this change is intentional.

-            description: "".to_string(), 
+            description: payment.description.unwrap_or_default(),

The OutgoingPaymentResponse struct doesn't appear to have a description field, so we need to determine if this is an oversight or if the field should not be populated for outgoing transactions.


Please run the above script to verify if the OutgoingPaymentResponse struct contains a description field. Once we confirm its definition, we can decide whether the empty string assignment for outgoing transactions is intentional or if it should be updated similarly to incoming transactions (i.e., using payment.description.unwrap_or_default()).


🏁 Script executed:

#!/bin/bash
# Search for the definition of OutgoingPaymentResponse to verify whether it includes a 'description' field.
rg "struct OutgoingPaymentResponse" -n .

Length of output: 233


Please run this script to verify if the OutgoingPaymentResponse struct contains any description field. This will help determine if populating a description field for outgoing transactions is needed or if the empty string assignment is intentional.


🏁 Script executed:

#!/bin/bash
# Search for any occurrence of 'description:' in the file to check if it's present in the OutgoingPaymentResponse struct.
rg "description:" -n ./crates/lni/phoenixd/api.rs

Length of output: 632


Action Required: Confirm description Field Usage in Outgoing Transactions

  • The code at lines 377–380 currently sets description to an empty string.
  • A diff suggestion proposes updating it to use payment.description.unwrap_or_default(), mirroring changes made for incoming transactions.
  • However, verification shows that the OutgoingPaymentResponse struct does not include a description field.
  • Please verify whether the outgoing transactions should include a description. If so, update the OutgoingPaymentResponse struct accordingly; otherwise, remove or repurpose the assignment.

Comment on lines +5 to +6
// #[serde(rename = "nodeId")] // Handle JSON field `nodeId`
// pub node_id: String,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Uncomment or remove commented code

There are commented-out lines for a node_id field with a JSON field rename. Either uncomment and implement this field if it's needed, or remove the commented code to improve code cleanliness.


🏁 Script executed:

#!/bin/bash
# Check if node_id is used elsewhere in the codebase
rg "node_id" --type rust -A 3 -B 3 crates/lni/cln/

Length of output: 433


Action Required: Remove Unused Commented Code in crates/lni/cln/types.rs

The commented-out lines for the node_id field (with its JSON rename) are not used elsewhere in the codebase. Please remove these lines to keep the code clean. If you intend to use this field in the future, uncomment and fully implement it; otherwise, removal is the best course of action.

  • File: crates/lni/cln/types.rs (lines 5–6)

Comment on lines 8 to 18
pub fn get_info(base: String, rune: String) -> Result<NodeInfo, ApiError> {
let req_url = format!("{}/v1/getinfo", base);
println!("Constructed URL: {} rune {}", req_url, rune);
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Rune", header::HeaderValue::from_str(&rune).unwrap());
let client = reqwest::blocking::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.default_headers(headers.clone())
.build()
.unwrap();

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve error handling and remove unsafe TLS configuration.

The current implementation uses .unwrap() which will panic if errors occur. Additionally, disabling certificate validation is a security risk in production environments.

Consider using proper error handling with the ? operator and making TLS validation configurable:

-pub fn get_info(base: String, rune: String) -> Result<NodeInfo, ApiError> {
+pub fn get_info(base: String, rune: String, skip_cert_verification: bool) -> Result<NodeInfo, ApiError> {
     let req_url = format!("{}/v1/getinfo", base);
-    println!("Constructed URL: {} rune {}", req_url, rune);
+    log::debug!("Constructed URL: {}", req_url);
     let mut headers = reqwest::header::HeaderMap::new();
-    headers.insert("Rune", header::HeaderValue::from_str(&rune).unwrap());
+    headers.insert(
+        "Rune", 
+        header::HeaderValue::from_str(&rune).map_err(|e| ApiError::Http { reason: e.to_string() })?
+    );
     let client = reqwest::blocking::ClientBuilder::new()
-        .danger_accept_invalid_certs(true)
+        .danger_accept_invalid_certs(skip_cert_verification)
         .default_headers(headers.clone())
-        .build()
-        .unwrap();
+        .build()
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn get_info(base: String, rune: String) -> Result<NodeInfo, ApiError> {
let req_url = format!("{}/v1/getinfo", base);
println!("Constructed URL: {} rune {}", req_url, rune);
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Rune", header::HeaderValue::from_str(&rune).unwrap());
let client = reqwest::blocking::ClientBuilder::new()
.danger_accept_invalid_certs(true)
.default_headers(headers.clone())
.build()
.unwrap();
pub fn get_info(base: String, rune: String, skip_cert_verification: bool) -> Result<NodeInfo, ApiError> {
let req_url = format!("{}/v1/getinfo", base);
log::debug!("Constructed URL: {}", req_url);
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
"Rune",
header::HeaderValue::from_str(&rune).map_err(|e| ApiError::Http { reason: e.to_string() })?
);
let client = reqwest::blocking::ClientBuilder::new()
.danger_accept_invalid_certs(skip_cert_verification)
.default_headers(headers.clone())
.build()
.map_err(|e| ApiError::Http { reason: e.to_string() })?;
// ... (remaining implementation)
}

Comment on lines 322 to 325
description: "".to_string(),
description_hash: "".to_string(),
payer_note: Some(inv.payer_note.unwrap_or("".to_string())),
external_id: Some(inv.external_id.unwrap_or("".to_string())),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Changed behavior for description field.

You've changed the behavior of the description field to always set it to an empty string, rather than using the value from the invoice. Make sure this is intentional as it could be a regression.

-                description:  "".to_string(),
+                description: inv.description.unwrap_or_default(),

Let's check how this field is handled elsewhere in the codebase:


🏁 Script executed:

#!/bin/bash
# Check how description is handled in other Transaction creation code

# Look for patterns where Transaction struct is created
rg -A 20 "Transaction \{" --glob "*.rs" | grep -A 1 "description:" | grep -v "description_hash"

Length of output: 562


Critical: Inconsistent Handling of the description Field

The current implementation in crates/lni/phoenixd/api.rs (lines 322–325) still hard-codes the description as an empty string, which deviates from the pattern observed elsewhere where the field is set from the invoice using unwrap_or_default(). In other parts of the codebase, we see assignments like:

  • description: description.unwrap_or_default(),
  • description: inv.description.unwrap_or_default(),

This inconsistency suggests that the hard-coded empty string might be an unintentional regression. Please verify whether the change was purposeful. If not, update the code to consistently use the invoice-provided description. For example:

-                description:  "".to_string(),
+                description: inv.description.unwrap_or_default(),

Ensure that this update aligns with the overall behavior expected for transaction creation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "".to_string(),
description_hash: "".to_string(),
payer_note: Some(inv.payer_note.unwrap_or("".to_string())),
external_id: Some(inv.external_id.unwrap_or("".to_string())),
description: inv.description.unwrap_or_default(),
description_hash: "".to_string(),
payer_note: Some(inv.payer_note.unwrap_or("".to_string())),
external_id: Some(inv.external_id.unwrap_or("".to_string())),

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
crates/lni/cln/api.rs (2)

8-30: ⚠️ Potential issue

Use HTTP GET method and improve error handling for getinfo endpoint.

The current implementation uses a POST request for the /v1/getinfo endpoint, but according to RESTful principles, it should be a GET request since it's retrieving information. Also, using .unwrap() is dangerous as it will panic if an error occurs.

pub fn get_info(url: String, rune: String) -> Result<NodeInfo, ApiError> {
    let req_url = format!("{}/v1/getinfo", url);
-    println!("Constructed URL: {} rune {}", req_url, rune);
+    println!("Constructed URL: {}", req_url); // Don't log sensitive rune values
    let client = clnrest_client(rune);
    let response = client
-        .post(&req_url)
+        .get(&req_url)
        .header("Content-Type", "application/json")
        .send()
-        .unwrap();
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
    let response_text = response.text().unwrap();
    println!("Raw response: {}", response_text);

102-110: 🛠️ Refactor suggestion

Improve error handling and make TLS validation configurable in client builder.

Using .unwrap() can lead to panics, and disabling certificate validation is a security risk in production. Make certificate validation configurable and add proper error handling.

-fn clnrest_client(rune: String) -> reqwest::blocking::Client {
+fn clnrest_client(rune: String, skip_cert_verification: bool) -> Result<reqwest::blocking::Client, ApiError> {
    let mut headers = reqwest::header::HeaderMap::new();
-    headers.insert("Rune", header::HeaderValue::from_str(&rune).unwrap());
+    headers.insert(
+        "Rune", 
+        header::HeaderValue::from_str(&rune)
+            .map_err(|e| ApiError::Http { reason: e.to_string() })?
+    );
    
-    reqwest::blocking::ClientBuilder::new()
-        .danger_accept_invalid_certs(true)
+    reqwest::blocking::ClientBuilder::new()
+        .danger_accept_invalid_certs(skip_cert_verification)
        .default_headers(headers)
        .build()
-        .unwrap()
+        .map_err(|e| ApiError::Http { reason: e.to_string() })
}

Then update the function call in get_info:

-    let client = clnrest_client(rune);
+    let client = clnrest_client(rune, true)?; // Consider making this false in production
🧹 Nitpick comments (6)
readme.md (5)

118-118: Fix heading level for the .env section.

Markdown analysis recommends incrementing headings in order and using setext style. Apply this diff:

-### .env
+## .env
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-124: Specify a language for the fenced code block.

It's good practice to label code blocks for proper syntax highlighting and to satisfy markdown lint rules.

-```
+```shell
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


135-136: Adjust list indentation for markdown compliance.

The markdown linter reports an indentation mismatch. You can correct it as follows:

-    - `cd bindings/lni_nodejs && cargo build --release && yarn build`
+  - `cd bindings/lni_nodejs && cargo build --release && yarn build`
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


136-136: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


138-138: Fix naming to “Node.js” and remove double punctuation.

Minor typographical issue with official project naming and extra dots.

-  - nodejs - native modules (electron, vercel etc..)
+  - Node.js - native modules (electron, vercel, etc.)
🧰 Tools
🪛 LanguageTool

[uncategorized] ~138-~138: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~138-~138: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


275-276: Convert the bare link into a proper Markdown hyperlink.

Markdown linting discourages bare URLs. A small formatting tweak helps maintain clarity.

-Facade REST API? - Use the same api as phoenixd https://phoenix.acinq.co/server/api 
+Facade REST API? - Use the same api as [phoenixd](https://phoenix.acinq.co/server/api)
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

276-276: Bare URL used
null

(MD034, no-bare-urls)

crates/lni/cln/api.rs (1)

66-70: Remove unnecessary parentheses in condition check.

The parentheses around the condition are unnecessary and not idiomatic Rust.

-    if (fetch_invoice_resp.invoice.is_empty()) {
+    if fetch_invoice_resp.invoice.is_empty() {
        return Err(ApiError::Json {
            reason: "Missing BOLT 12 invoice".to_string(),
        });
    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0207cbf and e7343aa.

📒 Files selected for processing (4)
  • crates/lni/cln/api.rs (1 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/cln/types.rs (1 hunks)
  • readme.md (4 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
readme.md

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


136-136: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Bare URL used
null

(MD034, no-bare-urls)

🪛 LanguageTool
readme.md

[uncategorized] ~138-~138: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~138-~138: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~252-~252: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)

🔇 Additional comments (8)
crates/lni/cln/types.rs (1)

5-6: Remove or implement the commented-out node_id field.

These lines remain unused or unimplemented. This issue was previously flagged in a past review and still applies.

readme.md (3)

125-126: Environment variables look good.


139-150: No concerns with this native module snippet.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


202-251: Sequence diagram addition looks great.

crates/lni/cln/lib.rs (4)

9-13: Configuration struct looks good.


15-19: Node struct definitions are proper.


21-47: CLN node implementation logic is straightforward.


50-114: Test module is well-structured.

Comment on lines +19 to +29
#[derive(Debug, Deserialize)]
pub struct PayResponse {
pub destination: String,
pub payment_hash: String,
pub created_at: f64,
pub parts: i32,
pub amount_msat: i64,
pub amount_sent_msat: i64,
pub payment_preimage: String,
pub status: String,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Confirm the need for signed integers in payment fields.

Payment-related amounts are typically non-negative. Consider verifying if i64 is required or if u64 would be more appropriate to avoid potential confusion or unintended behavior.


🏁 Script executed:

#!/bin/bash
# Description: Check references to PayResponse fields to confirm negative amounts aren’t expected.

rg -A 5 $'PayResponse'

Length of output: 1856


Payment Amount Type: Switch to Unsigned

After verifying the usage of the PayResponse struct across the codebase, there’s no indication that negative values are ever expected for payment amounts. Since fields like amount_msat and amount_sent_msat represent inherently non-negative values, it would be more precise and safer to use u64 instead of i64.

  • In crates/lni/cln/types.rs, update the fields as follows:
    -    pub amount_msat: i64,
    -    pub amount_sent_msat: i64,
    +    pub amount_msat: u64,
    +    pub amount_sent_msat: u64,

Please review any external API constraints or downstream logic to ensure that switching to an unsigned type aligns with all expectations.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[derive(Debug, Deserialize)]
pub struct PayResponse {
pub destination: String,
pub payment_hash: String,
pub created_at: f64,
pub parts: i32,
pub amount_msat: i64,
pub amount_sent_msat: i64,
pub payment_preimage: String,
pub status: String,
}
#[derive(Debug, Deserialize)]
pub struct PayResponse {
pub destination: String,
pub payment_hash: String,
pub created_at: f64,
pub parts: i32,
pub amount_msat: u64,
pub amount_sent_msat: u64,
pub payment_preimage: String,
pub status: String,
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
bindings/lni_react_native/example/src/App.tsx (1)

7-8: Consider removing commented-out Db code

Since the Db class has been removed from the bindings (as seen in index.js changes), you should consider removing these commented-out lines that reference it, as they're likely no longer relevant.

Also applies to: 59-72

bindings/lni_nodejs/main.mjs (1)

90-95: Added main function with call to cln()

The new main function currently only calls cln() with phoenixd() commented out. Consider providing a way to run either or both functions, perhaps based on environment configuration or command-line arguments.

async function main() {
-  // phoenixd();
-  cln();
+  const nodeType = process.env.NODE_TYPE || 'cln';
+  if (nodeType === 'phoenixd' || nodeType === 'all') {
+    await phoenixd();
+  }
+  if (nodeType === 'cln' || nodeType === 'all') {
+    await cln();
+  }
}
readme.md (1)

276-276: Fix markdown formatting for URL.

The URL should be enclosed in angle brackets to comply with Markdown standards.

-- [ ] Facade REST API? - Use the same api as phoenixd https://phoenix.acinq.co/server/api as a facade in front of any lightning node implementation. 
+- [ ] Facade REST API? - Use the same api as phoenixd <https://phoenix.acinq.co/server/api> as a facade in front of any lightning node implementation.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

276-276: Bare URL used
null

(MD034, no-bare-urls)

bindings/lni_nodejs/src/cln.rs (2)

42-70: Commented code should be removed or completed.

There are several commented-out method implementations that appear to be placeholders or copied from PhoenixdNode. Consider either implementing these methods for ClnNode or removing the commented code.


90-147: Commented test code should be updated for ClnNode.

The test code is commented out and still references PhoenixdNode and related structures. Consider either implementing proper tests for ClnNode or removing the commented code.

crates/lni/cln/lib.rs (1)

79-90: Improve error message in get_info test.

The error message in the test_get_info panic mentions "Failed to get offer" which is not accurate for a get_info call.

-                panic!("Failed to get offer: {:?}", e);
+                panic!("Failed to get node info: {:?}", e);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7343aa and 61a4378.

📒 Files selected for processing (10)
  • bindings/lni_nodejs/index.d.ts (1 hunks)
  • bindings/lni_nodejs/index.js (1 hunks)
  • bindings/lni_nodejs/main.mjs (1 hunks)
  • bindings/lni_nodejs/src/cln.rs (1 hunks)
  • bindings/lni_nodejs/src/lib.rs (1 hunks)
  • bindings/lni_react_native/example/src/App.tsx (2 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/phoenixd/lib.rs (2 hunks)
  • crates/lni/types.rs (2 hunks)
  • readme.md (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • bindings/lni_nodejs/src/lib.rs
  • crates/lni/types.rs
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
readme.md

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


136-136: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Bare URL used
null

(MD034, no-bare-urls)

🪛 LanguageTool
readme.md

[uncategorized] ~138-~138: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~138-~138: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~252-~252: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)

🔇 Additional comments (21)
crates/lni/phoenixd/lib.rs (2)

146-149: Static reference rename: TEST_OFFER -> TEST_RECEIVER_OFFER

The rename of both the static reference and the environment variable it's accessing to TEST_RECEIVER_OFFER improves code clarity by better specifying the purpose of this offer - it's specifically a receiver offer.


193-193: Updated function call with renamed variable

The function call has been updated to use the renamed TEST_RECEIVER_OFFER variable, maintaining consistency with the static reference rename.

bindings/lni_nodejs/index.js (2)

313-313: Updated imports to include ClnNode

The imports from the native binding now include ClnNode instead of previously imported entities like InvoiceType and Db. This change aligns with the core lightning integration.


316-316: Added ClnNode to exports

Now exporting the new ClnNode class, which will allow users of this module to interact with Core Lightning nodes.

bindings/lni_react_native/example/src/App.tsx (2)

13-13: Import rename: TEST_OFFER -> TEST_RECEIVER_OFFER

Updated the imported environment variable name to be consistent with the changes made in other files.


75-75: Updated variable usage in payOffer method

Correctly updated the function call to use the renamed TEST_RECEIVER_OFFER variable.

bindings/lni_nodejs/main.mjs (4)

1-1: Updated import to include ClnNode

The import statement now includes ClnNode alongside PhoenixdNode, reflecting the addition of Core Lightning support.


5-46: Refactored existing code into phoenixd() function

The original implementation has been cleanly encapsulated within an async function phoenixd(), making the code more modular.


31-31: Updated environment variable reference

Consistently updated the environment variable name to TEST_RECEIVER_OFFER to match changes in other files.


48-88: Added new cln() function for Core Lightning integration

New function to handle interactions with a Core Lightning node via the ClnNode class. The implementation is similar to the phoenixd function but uses different configuration parameters (CLN_URL and CLN_RUNE).

Note that several operations are commented out - is this intentional as placeholders for future implementation, or should these be uncommented and tested?

Can you verify which operations are currently supported by the new ClnNode implementation?

readme.md (4)

123-124: Environment variable name change noted.

The renaming from TEST_OFFER to TEST_RECEIVER_OFFER provides better clarity about the variable's purpose.


125-126: New Core Lightning environment variables are properly documented.

The addition of CLN_URL and CLN_RUNE environment variables is essential for the Core Lightning integration.


135-135: Build command improved for production use.

The updated build command now properly includes cargo clean and uses the --release flag, which is better for production deployments.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

135-135: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


202-251: Excellent sequence diagram addition.

The sequence diagram clearly illustrates the interactions between application layers, bindings, LNI core, and lightning nodes. This significantly improves documentation for developers.

bindings/lni_nodejs/index.d.ts (1)

17-24: Well-structured ClnNode class declaration.

The new ClnNode class follows the same pattern as the existing PhoenixdNode class, maintaining consistency in the API design while supporting the Core Lightning implementation. The method signatures are appropriate for the required functionality.

bindings/lni_nodejs/src/cln.rs (2)

1-40: Good implementation of ClnNode structure and core methods.

The implementation properly defines the ClnNode structure with appropriate getter methods and the get_info() function. Error handling is correctly implemented by converting Rust errors to NAPI errors.


72-88: Proper implementation of pay_offer method.

The pay_offer method is well-implemented with correct parameter handling and error conversion. It matches the TypeScript declaration and follows the established API pattern.

crates/lni/cln/lib.rs (4)

9-19: Well-defined ClnConfig and ClnNode structures.

The structures are properly defined with the necessary fields and appropriate feature flags for NAPI integration.


21-48: Clean implementation of ClnNode methods.

The methods are well-implemented with proper error handling and consistent parameter passing to the API functions.


58-77: Good test setup with environment variables.

The test setup properly uses environment variables with appropriate error messages when they're missing.


92-113:

❓ Verification inconclusive

Hardcoded amount in pay_offer test.

The test for pay_offer uses a hardcoded amount of 3000 millisatoshis. This could fail if the offer requires a specific amount.

Consider adding a check to verify the offer's required amount or making this test more flexible:


🏁 Script executed:

#!/bin/bash
# Check whether the codebase has any logic to handle offers with specific amount requirements

# Search for code that might handle offer amount requirements
rg -A 3 -B 3 "amount.*required|required.*amount" --glob "*.rs"

Length of output: 64


ACTION: Revisit and update the pay_offer test for amount flexibility

  • The test in crates/lni/cln/lib.rs currently uses a hardcoded value (3000) for the payment amount.
  • Our search for any offer-specific amount validation logic yielded no conclusive evidence.
  • Please either:
    • Retrieve and use the required amount dynamically (if such metadata is available), or
    • Clearly document that the fixed amount is valid for the current offer context.
  • Manual verification is needed to ensure that the underlying business logic hasn’t changed and that the hardcoded value still meets offer requirements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (6)
crates/lni/phoenixd/api.rs (2)

240-243: ⚠️ Potential issue

Critical: Inconsistent Handling of the description Field

The current implementation still hard-codes the description as an empty string, which deviates from the pattern observed elsewhere where the field is set from the invoice using unwrap_or_default().

Apply this diff to maintain consistency:

-                description:  "".to_string(),
+                description: inv.description.unwrap_or_default(),

295-296: ⚠️ Potential issue

Inconsistent Handling of the description Field

Similar to the issue above, the description field is hard-coded as an empty string rather than using the value from the payment.

Apply this diff to maintain consistency:

-            description: "".to_string(), 
+            description: payment.description.unwrap_or_default(),
crates/lni/cln/api.rs (4)

8-30: ⚠️ Potential issue

Use HTTP GET method and improve error handling in the get_info function.

The /v1/getinfo endpoint should use the GET method instead of POST, and there are multiple instances of .unwrap() that can cause runtime panics in production. Additionally, using println! for logging is not suitable for production code.

pub fn get_info(url: String, rune: String) -> Result<NodeInfo, ApiError> {
    let req_url = format!("{}/v1/getinfo", url);
-    println!("Constructed URL: {} rune {}", req_url, rune);
+    log::debug!("Constructed URL: {}", req_url);
    let client = clnrest_client(rune);
    let response = client
-        .post(&req_url)
+        .get(&req_url)
        .header("Content-Type", "application/json")
        .send()
-        .unwrap();
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
-    let response_text = response.text().unwrap();
-    println!("Raw response: {}", response_text);
+    let response_text = response.text()
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
+    log::debug!("Raw response: {}", response_text);
    let info: InfoResponse = serde_json::from_str(&response_text)?;

32-64: ⚠️ Potential issue

Use async client for async function and improve error handling in pay_offer.

The function is marked as async but uses blocking HTTP methods, which defeats the purpose of async programming. Additionally, all .unwrap() calls should be replaced with proper error handling.

pub async fn pay_offer(
    url: String,
    rune: String,
    offer: String,
    amount_msats: i64,
    payer_note: Option<String>,
) -> Result<PayInvoiceResponse, ApiError> {
    let fetch_invoice_url = format!("{}/v1/fetchinvoice", url);
-    let client = clnrest_client(rune);
+    let client = clnrest_async_client(rune).await?;
-    let response: reqwest::blocking::Response = client
+    let response = client
        .post(&fetch_invoice_url)
        .header("Content-Type", "application/json")
        .json(&serde_json::json!({
            "offer": offer,
            "amount_msat": amount_msats,
            "payer_note": payer_note,
            "timeout": 60,
        }))
        .send()
-        .unwrap();
+        .await.map_err(|e| ApiError::Http { reason: e.to_string() })?;
-    let response_text = response.text().unwrap();
-    let response_text = response_text.as_str();
+    let response_text = response.text()
+        .await
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;

You'll also need to implement an async version of the client builder:

async fn clnrest_async_client(rune: String) -> Result<reqwest::Client, ApiError> {
    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert(
        "Rune", 
        header::HeaderValue::from_str(&rune)
            .map_err(|e| ApiError::Http { reason: e.to_string() })?
    );
    
    reqwest::ClientBuilder::new()
        .danger_accept_invalid_certs(true) // Consider making this configurable
        .default_headers(headers)
        .build()
        .map_err(|e| ApiError::Http { reason: e.to_string() })
}

72-93: ⚠️ Potential issue

Use async methods and proper error handling for payment request.

Similar to the fetch invoice request, this code needs to use async methods and proper error handling to avoid unwraps.

    // now pay the bolt 12 invoice lni
    let pay_url = format!("{}/v1/pay", url);
-    let pay_response: reqwest::blocking::Response = client
+    let pay_response = client
        .post(&pay_url)
        .header("Content-Type", "application/json")
        .json(&serde_json::json!({
            "bolt11": fetch_invoice_resp.invoice.to_string(),
-            "maxfeepercent": 1, // TODO read from config
+            "maxfeepercent": 1, // TODO: Make this configurable
            "retry_for": 60,
        }))
        .send()
-        .unwrap();
-    let pay_response_text = pay_response.text().unwrap();
-    let pay_response_text = pay_response_text.as_str();
+        .await
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
+    let pay_response_text = pay_response.text()
+        .await
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
    let pay_resp: PayResponse = match serde_json::from_str(&pay_response_text) {
        Ok(resp) => resp,
        Err(e) => {
+            log::error!("Failed to parse pay response: {:?}", e);
            return Err(ApiError::Json {
                reason: pay_response_text.to_string(),
            })
        }
    };

179-187: ⚠️ Potential issue

Improve error handling and remove unsafe TLS configuration.

The current implementation uses .unwrap() which will panic if errors occur. Additionally, disabling certificate validation is a security risk in production environments.

-fn clnrest_client(rune: String) -> reqwest::blocking::Client {
+fn clnrest_client(rune: String) -> Result<reqwest::blocking::Client, ApiError> {
    let mut headers = reqwest::header::HeaderMap::new();
-    headers.insert("Rune", header::HeaderValue::from_str(&rune).unwrap());
+    headers.insert(
+        "Rune", 
+        header::HeaderValue::from_str(&rune).map_err(|e| ApiError::Http { reason: e.to_string() })?
+    );
-    reqwest::blocking::ClientBuilder::new()
-        .danger_accept_invalid_certs(true)
+    reqwest::blocking::ClientBuilder::new()
+        .danger_accept_invalid_certs(false) // Consider making this configurable
        .default_headers(headers)
        .build()
-        .unwrap()
+        .map_err(|e| ApiError::Http { reason: e.to_string() })
}
🧹 Nitpick comments (14)
crates/lni/phoenixd/api.rs (1)

181-187: Clean Up Commented Code

The file contains multiple blocks of commented-out code related to parameter handling. This can make the code harder to read and maintain.

Either remove these commented sections entirely if they're no longer needed, or add clear comments explaining why they're preserved for future reference.

Also applies to: 199-205, 256-263

readme.md (3)

118-130: Improve Markdown Formatting Consistency

There are several formatting issues in the markdown file that should be addressed:

  1. The heading hierarchy is inconsistent (jumping from h1 to h3)
  2. The code block at line 119 is missing a language specifier

Suggested fixes:

-### .env
+## Environment Variables

+env
TEST_RECEIVER_OFFER=lno**
PHOENIX_MOBILE_OFFER=lno***


<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

---

118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)

---

119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

</details>

</details>

---

`141-153`: **Fix Node.js Naming and Punctuation**

Minor language and formatting issues in this section:
1. The official spelling is "Node.js" (with capitalized "N" and dot)
2. Double punctuation in "etc.."


```diff
-nodejs - native modules (electron, vercel etc..)
+Node.js - native modules (electron, vercel, etc.)
🧰 Tools
🪛 LanguageTool

[uncategorized] ~141-~141: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~141-~141: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

142-142: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


279-279: Format URL as Proper Markdown Link

The Phoenix API URL should be formatted as a proper markdown link rather than a bare URL.

-- [ ] Facade REST API? - Use the same api as phoenixd https://phoenix.acinq.co/server/api as a facade in front of any lightning node implementation. 
+- [ ] Facade REST API? - Use the same api as phoenixd [Phoenix API](https://phoenix.acinq.co/server/api) as a facade in front of any lightning node implementation. 
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

279-279: Bare URL used
null

(MD034, no-bare-urls)

crates/lni/cln/api.rs (3)

66-70: Remove unnecessary parentheses in if condition.

The extra parentheses around the condition in the if statement are unnecessary and inconsistent with Rust style.

-    if (fetch_invoice_resp.invoice.is_empty()) {
+    if fetch_invoice_resp.invoice.is_empty() {
        return Err(ApiError::Json {
            reason: "Missing BOLT 12 invoice".to_string(),
        });
    }

79-80: Make the maxfeepercent configurable.

The maxfeepercent is hardcoded with a TODO comment. Consider making this configurable through a parameter.

-            "maxfeepercent": 1, // TODO read from config
+            "maxfeepercent": config.max_fee_percent.unwrap_or(1), // Default to 1%

This would require adding the configuration parameter to the function signature and relevant structs.


167-177: Simplify list_transactions implementation.

The current implementation with the match is unnecessarily verbose. This can be simplified.

pub fn list_transactions(
    url: String,
    rune: String,
    from: i64,
    limit: i64,
) -> Result<Vec<Transaction>, ApiError> {
-    match lookup_invoice(url, rune, None, Some(from), Some(limit)) {
-        Ok(transactions) => Ok(transactions),
-        Err(e) => Err(e),
-    }
+    lookup_invoice(url, rune, None, Some(from), Some(limit))
}
bindings/lni_nodejs/src/cln.rs (3)

42-59: Remove or implement the commented-out make_invoice method.

There's a large block of commented-out code for a make_invoice method. This should either be properly implemented or removed.

Either implement the method with the proper parameters and functionality, or remove the commented-out code entirely to keep the codebase clean.


61-72: Improve error handling in lookup_invoice.

The code for handling transactions when none are found could be clearer and more specific.

  pub async fn lookup_invoice(&self, payment_hash: String) -> napi::Result<lni::Transaction> {
    let txn = lni::cln::api::lookup_invoice(
      self.inner.url.clone(),
      self.inner.rune.clone(),
      Some(payment_hash),
      None,
      None,
    )
    .map_err(|e| napi::Error::from_reason(e.to_string()))?;
-    Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason("No transaction found"))?)
+    txn.into_iter().next().ok_or_else(|| napi::Error::from_reason(format!("No transaction found for payment hash: {}", payment_hash)))
  }

108-145: Consider implementing or removing the test module.

There's a large block of commented-out test code. This should either be implemented with the proper CLN test configuration or removed.

If you plan to use this test module, update it for CLN testing with proper URLs and authentication. Otherwise, consider removing it to keep the codebase clean.

crates/lni/cln/lib.rs (4)

64-75: Rename method to match functionality.

The list_transactions method actually calls lookup_invoice internally. This can be confusing. Consider renaming the method or using the correct API call.

pub async fn list_transactions(
    &self,
    params: ListTransactionsParams,
) -> Result<Vec<crate::Transaction>, ApiError> {
-    crate::cln::api::lookup_invoice(
+    crate::cln::api::list_transactions(
        self.url.clone(),
        self.rune.clone(),
-        None,
-        Some(params.from),
-        Some(params.limit),
+        params.from,
+        params.limit,
    )
}

119-120: Fix error message in test_get_info.

The error message says "Failed to get offer" but it should be "Failed to get info".

-                panic!("Failed to get offer: {:?}", e);
+                panic!("Failed to get info: {:?}", e);

142-143: Fix error message in test_pay_offer.

The error message says "Failed to get offer" but it should be "Failed to pay offer".

-                panic!("Failed to get offer: {:?}", e);
+                panic!("Failed to pay offer: {:?}", e);

173-176: Improve assertion in test_list_transactions.

The current assertion txns.len() >= 0 is always true and doesn't provide meaningful validation. Consider a more specific test.

-                assert!(
-                    txns.len() >= 0,
-                    "Should contain at least zero or one transaction"
-                );
+                // Print the count for debugging
+                println!("Found {} transactions", txns.len());
+                
+                // Verify transaction structure if any exist
+                if !txns.is_empty() {
+                    let first_txn = &txns[0];
+                    assert!(!first_txn.payment_hash.is_empty(), "Transaction should have a payment hash");
+                }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 61a4378 and b370cd6.

📒 Files selected for processing (17)
  • bindings/lni_nodejs/index.d.ts (1 hunks)
  • bindings/lni_nodejs/main.mjs (1 hunks)
  • bindings/lni_nodejs/src/cln.rs (1 hunks)
  • bindings/lni_nodejs/src/lib.rs (1 hunks)
  • bindings/lni_nodejs/src/phoenixd.rs (1 hunks)
  • bindings/lni_react_native/example/src/App.tsx (3 hunks)
  • bindings/lni_uniffi/src/lib.rs (1 hunks)
  • bindings/lni_uniffi/src/lni.udl (3 hunks)
  • crates/lni/cln/api.rs (1 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/cln/types.rs (1 hunks)
  • crates/lni/lib.rs (1 hunks)
  • crates/lni/phoenixd/api.rs (10 hunks)
  • crates/lni/phoenixd/lib.rs (5 hunks)
  • crates/lni/phoenixd/types.rs (1 hunks)
  • crates/lni/types.rs (3 hunks)
  • readme.md (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • crates/lni/phoenixd/lib.rs
  • bindings/lni_react_native/example/src/App.tsx
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
readme.md

118-118: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


118-118: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


119-119: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


138-138: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


139-139: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


142-142: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


279-279: Bare URL used
null

(MD034, no-bare-urls)

🪛 LanguageTool
readme.md

[uncategorized] ~141-~141: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~141-~141: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~255-~255: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)

🔇 Additional comments (28)
bindings/lni_nodejs/src/lib.rs (3)

7-7: Improved type exports for better API clarity

The explicit export of specific types from the lni::types module provides better clarity about what types are available to consumers of this API. This is a good practice that makes the public interface more discoverable.


9-10: Logical module organization

Moving the phoenixd module declaration after the public use declarations maintains good code organization, ensuring that its export (PhoenixdNode) remains accessible while keeping related code grouped together.


12-13: Good addition of Core Lightning support

The addition of the cln module and export of ClnNode appropriately implements the Core Lightning functionality mentioned in the PR objectives. This is a well-structured way to add new functionality while keeping it separate from the existing phoenixd implementation.

bindings/lni_uniffi/src/lib.rs (1)

2-4: Simplified import structure

Replacing specific imports with wildcard imports simplifies the code and makes it more maintainable. The addition of the new lni::cln module import properly aligns with the Core Lightning integration goal of this PR.

bindings/lni_uniffi/src/lni.udl (3)

99-100: Enhanced transaction metadata support

The addition of payer_note and external_id fields to the Transaction dictionary provides useful metadata for transactions. The payer_note field will be particularly valuable for bolt12 offers, while external_id can be used for bolt11 invoice identification.


199-199: Critical payment tracking field added

Adding the payment_hash field to PayInvoiceResponse is essential for tracking and identifying payments. This field is a standard identifier in the Lightning Network protocol and enhances the API's compliance with Lightning standards.


223-227: Simplified transaction filtering

The streamlined ListTransactionsParams dictionary now focuses on pagination (from, limit) and specific transaction lookup (payment_hash), removing unnecessary fields. This simplification makes the API more focused and easier to use.

bindings/lni_nodejs/src/phoenixd.rs (2)

93-93: Updated parameter type for consistency

Changing the parameter type from lni::phoenixd::lib::ListTransactionsParams to crate::ListTransactionsParams ensures consistency with the simplified transaction params structure defined at the crate level.


100-100:

❓ Verification inconclusive

Verify impact of parameter changes

Passing None as the until parameter (and removing other parameters) aligns with the simplified ListTransactionsParams structure. This change simplifies the API but could affect existing functionality.


🏁 Script executed:

#!/bin/bash
# Check for any other usages of list_transactions to ensure they're compatible with the new parameter structure
grep -r "list_transactions" --include="*.rs" --include="*.ts" . | grep -v "None" || echo "No other implementations found"

# Check if there are any tests that might be affected by this change
find . -name "*test*.rs" -o -name "*test*.ts" | xargs grep -l "list_transactions" || echo "No tests found for list_transactions"

Length of output: 1156


Verify and confirm the new parameter usage across implementations

The change in bindings/lni_nodejs/src/phoenixd.rs (passing None for the until parameter) aligns with the updated, simplified ListTransactionsParams design. However, please verify that:

  • Other implementations (e.g., in bindings/lni_nodejs/src/cln.rs, crates/lni/cln/*, and crates/lni/phoenixd/*) correctly support this change.
  • The removal of additional parameters does not lead to unexpected behavior, especially since our search did not locate dedicated tests for list_transactions.

Ensure that downstream code calling this API is adjusted appropriately and consider adding relevant tests to cover this change if needed.

crates/lni/types.rs (3)

45-46: Good field additions for better transaction tracking

The new optional fields (payer_note and external_id) enhance the Transaction struct by providing support for both bolt12 and bolt11 protocol features. This addition properly maintains backward compatibility by making them optional.


174-174: Essential field addition to PayInvoiceResponse

Adding the payment_hash field to PayInvoiceResponse is necessary for uniquely identifying payments in the Lightning Network, which is critical for payment tracking and lookups.


203-209: Well-structured pagination and filtering parameters

The new ListTransactionsParams struct provides a clean interface for transaction listing with proper pagination (from, limit) and filtering (payment_hash) capabilities.

crates/lni/lib.rs (2)

23-28: Good modular architecture expansion

The addition of the types module to the phoenixd namespace and explicit exports of key structs improves the organization and accessibility of the code.


30-34: Excellent addition of Core Lightning support

The introduction of the cln module with its submodules (lib, api, types) establishes a clear parallel structure to the existing phoenixd module, facilitating multiple Lightning implementation support.

bindings/lni_nodejs/main.mjs (4)

1-1: Proper import for new node implementations

Adding the ClnNode import alongside PhoenixdNode properly supports the multi-implementation architecture being introduced.


5-42: Well-structured code refactoring

Encapsulating the phoenixd functionality into a dedicated function improves code organization and readability.


82-87: Clean main function implementation

The main() function now properly orchestrates both implementations, allowing for parallel testing and execution.


44-80:

✅ Verification successful

Good implementation of Core Lightning functionality

The cln() function mirrors the phoenixd implementation, providing a consistent interface for interacting with Core Lightning nodes.


🌐 Web query:

Does Core Lightning use InvoiceType.Bolt11 as shown in line 59?

💡 Result:

Core Lightning explicitly uses BOLT #11 as its standard for Lightning invoices, with its implementation deeply integrated into the codebase. The bolt11 terminology appears consistently across Core Lightning's JSON-RPC interface and documentation when handling invoices[1][3][12][13].

Key evidence from the search results:

  1. The JSON-RPC invoice command directly returns a "bolt11" field containing the BOLT #11-encoded invoice string[12][13].
  2. Unit tests specifically reference run-bolt11.c for validating BOLT #11 functionality[1].
  3. Core Lightning's documentation explicitly states: "returns some internal details, and a standard invoice string called bolt11 (named after the BOLT #11 lightning spec)"[12][13].
  4. Multiple live coding sessions focus on BOLT #11 implementation details in Core Lightning, including signature handling and bech32 encoding[1][4][7].

While the exact line number reference isn't visible in the provided sources, the pattern matches Core Lightning's convention of using bolt11 identifiers for BOLT #11-related code structures. The implementation follows the BOLT #11 specification from the Lightning Network RFCs[9], with explicit references to BOLT #11 tagged fields like r (routing info) and s (payment secrets) in the code analysis[4][7].

Citations:


Verified: Core Lightning Invoice Type Usage Correct

The usage of InvoiceType.Bolt11 in the cln() function is consistent with Core Lightning's implementation of the BOLT #11 standard. The code snippet correctly mirrors the structure seen in related implementations (e.g., phoenixd) and adheres to the established JSON-RPC conventions where BOLT #11 invoice strings are used.

  • File: bindings/lni_nodejs/main.mjs (Lines: 44-80)
  • Observation: The call to node.makeInvoice with invoiceType: InvoiceType.Bolt11 correctly aligns with Core Lightning's specification.

No modifications are necessary.

crates/lni/phoenixd/types.rs (5)

1-7: Good basic info response structure

The InfoResponse struct properly handles JSON field mapping between camelCase (nodeId) and snake_case (node_id), following Rust conventions.


9-21: Well-designed invoice request structure

The Bolt11Req struct contains all necessary fields for creating Lightning invoices with proper JSON field mapping.


23-49: Comprehensive invoice response structure

The InvoiceResponse struct captures all relevant details about an invoice, including payment tracking fields, timestamps, and protocol-specific fields (payer_note for bolt12, external_id for bolt11).


51-73: Complete outgoing payment response structure

The OutgoingPaymentResponse struct properly mirrors the invoice response structure but focuses on outgoing payment details, maintaining consistency in the API.


75-85: Concise payment response structure

The PayResponse struct provides the essential payment information needed after a successful payment operation.

crates/lni/cln/types.rs (2)

5-6: Action Required: Remove Unused Commented Code

The commented-out lines for the node_id field are not being used. Either uncomment and fully implement this field if needed, or remove these lines to keep the code clean.


25-26: Payment Amount Type: Switch to Unsigned

Payment amounts are inherently non-negative values. It would be more precise and safer to use u64 instead of i64 for the payment amount fields.

-    pub amount_msat: i64,
-    pub amount_sent_msat: i64,
+    pub amount_msat: u64,
+    pub amount_sent_msat: u64,
readme.md (1)

205-254: Excellent Sequence Diagram

The addition of the sequence diagram is excellent and provides valuable context for understanding the architecture and interactions between components. This significantly improves the documentation quality.

bindings/lni_nodejs/index.d.ts (1)

17-25: Well-Designed ClnNode Class Implementation

The new ClnNode class follows a consistent interface pattern matching the existing PhoenixdNode class. This is an excellent design choice that will make it easy for developers to switch between different node implementations without changing their code significantly.

The method signatures are consistent, and the class provides all the necessary functionality for interacting with a Core Lightning node.

crates/lni/cln/lib.rs (1)

95-98: Missing environment variable in README.

The test uses PHOENIX_MOBILE_OFFER environment variable, but this isn't documented in the README.

#!/bin/bash
# Check if PHOENIX_MOBILE_OFFER is documented in the README
grep -r "PHOENIX_MOBILE_OFFER" --include="README*" .

Please add the PHOENIX_MOBILE_OFFER environment variable to the .env section in the README to ensure developers can run the tests successfully.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
readme.md (5)

107-112: Fix Typographical and Formatting Errors in Troubleshooting Section
The header `*troubleshooting react-natve`: contains a typo ("react-natve" should be "react-native") and appears to have loose punctuation. Please correct the spelling and consider refining the formatting (and list indentations) for better readability.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

110-110: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


146-147: Correct Naming and Formatting for Node.js Section
The bullet point reads “- nodejs - native modules (electron, vercel etc..)”. Please replace “nodejs” with the officially styled “Node.js” and remove the extra period (use “etc.” instead). This ensures consistency and clarity.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~146-~146: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~146-~146: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

147-147: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


196-196: Clarify Tor Socks5 Proxy Instructions
The note “Use Tor socks if connecting to a .onion hidden service by passing in socks5 proxy. (TODO WIP)” is useful as a reminder. Consider providing further guidance or an example on how to configure the SOCKS5 proxy, or remove the TODO if it’s not planned for the near term.


268-277: Update Todo List Formatting and Content
The updated Todo list now includes new tasks (such as “Tor Socks5 fetch” and additional lightning node implementations). Please review the indentation and consistency of the list markers, as markdownlint has flagged some unordered list indentation issues. Ensure that the task statuses accurately reflect the current work plan.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

270-270: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


282-285: Refine To Research Section Formatting
In the “To Research” section, bare URLs are used (e.g., in the items regarding napi-rs and the Facade REST API). Consider replacing these with proper markdown links to improve readability and comply with markdown best practices. Also, check the list indentation to adhere to markdownlint guidelines.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

282-282: Bare URL used
null

(MD034, no-bare-urls)


285-285: Bare URL used
null

(MD034, no-bare-urls)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b370cd6 and f947c9f.

⛔ Files ignored due to path filters (1)
  • bindings/lni_react_native/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • bindings/lni_react_native/LniFramework.xcframework/Info.plist (2 hunks)
  • bindings/lni_react_native/build.sh (0 hunks)
  • bindings/lni_react_native/example/src/App.tsx (4 hunks)
  • bindings/lni_react_native/package.json (2 hunks)
  • bindings/lni_react_native/ubrn.config.yaml (1 hunks)
  • crates/lni/lib.rs (1 hunks)
  • readme.md (5 hunks)
💤 Files with no reviewable changes (1)
  • bindings/lni_react_native/build.sh
✅ Files skipped from review due to trivial changes (2)
  • bindings/lni_react_native/package.json
  • bindings/lni_react_native/ubrn.config.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • bindings/lni_react_native/example/src/App.tsx
  • crates/lni/lib.rs
🧰 Additional context used
🪛 LanguageTool
readme.md

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~146-~146: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~146-~146: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~260-~260: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)


[uncategorized] ~264-~264: The official spelling of this programming framework is “Node.js”.
Context: ... - [X] make interface - [X] napi-rs for nodejs - [X] uniffi bindings for Android and I...

(NODE_JS)

🪛 markdownlint-cli2 (0.17.2)
readme.md

110-110: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


123-123: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


123-123: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


124-124: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


143-143: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


144-144: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


147-147: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


270-270: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


282-282: Bare URL used
null

(MD034, no-bare-urls)


285-285: Bare URL used
null

(MD034, no-bare-urls)

🔇 Additional comments (5)
bindings/lni_react_native/LniFramework.xcframework/Info.plist (1)

11-11: Properly configured platform identifiers for iOS builds.

The changes correctly reorganize the framework architecture support by:

  1. Distinguishing between simulator and device builds for iOS arm64 architecture
  2. Adding explicit simulator variant identification with SupportedPlatformVariant
  3. Ensuring appropriate library identifiers for each target platform

This configuration follows Apple's XCFramework best practices and will ensure the correct binary is used when building for simulator versus physical device.

Also applies to: 20-21, 27-27

readme.md (4)

125-134: Confirm Environment Variables Update
New environment variables (TEST_RECEIVER_OFFER, PHOENIX_MOBILE_OFFER, CLN_URL, CLN_RUNE, CLN_TEST_PAYMENT_HASH) have been added. Ensure that these updates are consistent with related changes in code and documentation elsewhere in the project.


143-143: Enhanced Build Command for Node.js Bindings
The updated command (cd bindings/lni_nodejs && cargo clean && cargo build --release && yarn && yarn build) now enforces a release build and cleans the previous builds. This is a welcome improvement; please verify it aligns with your overall build workflow.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

143-143: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


148-158: Review Native Module Usage Example
The code snippet clearly demonstrates how to load a native Node.js module based on the platform and architecture. Just confirm that the constructed file path (../../code/lni/bindings/lni_nodejs/lni_js.${platform}-${arch}.node) is correct relative to the repository root.


210-259: New LNI Sequence Diagram Integration
The added LNI Sequence Diagram effectively visualizes interactions among the Application, Binding, LNI Core, and Lightning Node components. This visual aid is a valuable enhancement for the documentation. Please verify that the Mermaid syntax renders correctly in all intended environments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
readme.md (6)

107-114: Fix Typo and Improve Troubleshooting Section Formatting
The heading "*troubleshooting react-natve:" contains a typographical error and an informal style. Consider updating it to use a standard markdown heading (e.g., "### Troubleshooting React Native:") and refine the list items to avoid repetitive phrases (like repeatedly saying “for ios”).

-`*troubleshooting react-natve`: 
+### Troubleshooting React Native:
🧰 Tools
🪛 LanguageTool

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~109-~109: This phrase is duplicated. You should probably use “for ios” only once.
Context: ...swipe away app) - try updating the pods for ios cd example/ios && pod install --repo-update && cd ../ - for ios open the xcode app - lni/bindings/lni_r...

(PHRASE_REPETITION)


[uncategorized] ~114-~114: The official spelling of this programming framework is “Node.js”.
Context: ...talling the app from the mobile device nodejs ``` cd bindings/lni_nodejs cat main.mj...

(NODE_JS)

🪛 markdownlint-cli2 (0.17.2)

111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


124-136: Enhance the .env Section Formatting
The ".env" section would benefit from a more explicit code block language and consistent heading hierarchy. Specifying a language identifier (e.g., dotenv) in the fenced code block improves readability and helps with syntax highlighting.

-```
+```dotenv
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

124-124: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


124-124: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


125-125: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


141-146: Correct Unordered List Indentation in the Node.js Build Command
The build command line for the Node.js bindings is over-indented relative to its parent list item. To comply with markdown linting guidelines (MD007), please adjust the indentation (typically 2 spaces for nested items) for improved consistency and readability.

-    - `cd bindings/lni_nodejs && cargo clean && cargo build --release && yarn && yarn build`
+  - `cd bindings/lni_nodejs && cargo clean && cargo build --release && yarn && yarn build`
🧰 Tools
🪛 LanguageTool

[uncategorized] ~141-~141: The official spelling of this programming framework is “Node.js”.
Context: ...ASH=YOUR_HASH ``` Bindings ======== - nodejs - napi_rs - https://napi.rs/do...

(NODE_JS)

🪛 markdownlint-cli2 (0.17.2)

142-142: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


143-143: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


143-143: Bare URL used
null

(MD034, no-bare-urls)


144-144: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


145-145: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


147-160: Standardize Framework Naming and Punctuation in the Native Modules Section
References to “nodejs” should be updated to “Node.js” (notice the proper capitalization and punctuation). Additionally, adjust punctuation such as “etc..” to “etc.” and consider capitalizing technology names (e.g., Electron, Vercel) for clarity.

-- nodejs - native modules (electron, vercel etc..)
+- Node.js - native modules (Electron, Vercel, etc.)
🧰 Tools
🪛 LanguageTool

[uncategorized] ~147-~147: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~147-~147: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

148-148: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


269-278: Refine Todo List Indentation and Consistency
The todo items in this section (e.g., "Tor Socks5 fetch" and the sub-items under "implement lightning nodes") have inconsistent indentation according to markdown guidelines. Adjust the nested bullet points (using 2 spaces per level) to improve structure and readability.

-    - [X] phoenixd
-    - [X] cln
+  - [X] phoenixd
+  - [X] cln
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


278-278: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


283-287: Format Bare URLs in the "To Research" Section
The “To Research” section includes bare URLs. For better readability and usability, convert these into proper markdown links. For example, replace
https://napi.rs/docs/introduction/simple-package
with something like [napi-rs docs](https://napi.rs/docs/introduction/simple-package).

- - [X] napi-rs https://napi.rs/docs/introduction/simple-package
+ - [X] napi-rs [docs](https://napi.rs/docs/introduction/simple-package)
- - [ ] Facade REST API? - Use the same api as phoenixd https://phoenix.acinq.co/server/api as a facade in front of any lightning node implementation.
+ - [ ] Facade REST API? - Use the same API as Phoenixd ([phoenix.acinq.co/server/api](https://phoenix.acinq.co/server/api)) as a facade in front of any lightning node implementation.
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

283-283: Bare URL used
null

(MD034, no-bare-urls)


286-286: Bare URL used
null

(MD034, no-bare-urls)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f947c9f and 7fa7f51.

📒 Files selected for processing (3)
  • bindings/lni_react_native/build.sh (1 hunks)
  • bindings/lni_react_native/example/src/App.tsx (4 hunks)
  • readme.md (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • bindings/lni_react_native/build.sh
  • bindings/lni_react_native/example/src/App.tsx
🧰 Additional context used
🪛 LanguageTool
readme.md

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~109-~109: This phrase is duplicated. You should probably use “for ios” only once.
Context: ...swipe away app) - try updating the pods for ios cd example/ios && pod install --repo-update && cd ../ - for ios open the xcode app - lni/bindings/lni_r...

(PHRASE_REPETITION)


[uncategorized] ~147-~147: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~147-~147: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~261-~261: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)


[uncategorized] ~265-~265: The official spelling of this programming framework is “Node.js”.
Context: ... - [X] make interface - [X] napi-rs for nodejs - [X] uniffi bindings for Android and I...

(NODE_JS)

🪛 markdownlint-cli2 (0.17.2)
readme.md

111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


124-124: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


124-124: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


125-125: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


144-144: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


145-145: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


148-148: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


278-278: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


283-283: Bare URL used
null

(MD034, no-bare-urls)


286-286: Bare URL used
null

(MD034, no-bare-urls)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

♻️ Duplicate comments (7)
crates/lni/phoenixd/api.rs (2)

240-243: ⚠️ Potential issue

Critical: Inconsistent Handling of the description Field

The current implementation in crates/lni/phoenixd/api.rs (lines 240-243) still hard-codes the description as an empty string, which deviates from the pattern observed elsewhere where the field is set from the invoice using unwrap_or_default().

This inconsistency suggests that the hard-coded empty string might be an unintentional regression.

Apply this diff to fix the issue:

-                description:  "".to_string(),
+                description: inv.description.unwrap_or_default(),

295-298: 🛠️ Refactor suggestion

Consistent handling of optional fields in transactions

The code now correctly handles the optional payer_note and external_id fields for outgoing transactions, similar to how they're handled for incoming transactions. This ensures consistency in how transaction data is processed.

However, note that the description field is still set to an empty string instead of using data from the response, which differs from the handling of incoming transactions.

-            description: "".to_string(), 
+            description: payment.description.unwrap_or_default(),
crates/lni/cln/lib.rs (1)

63-78: ⚠️ Potential issue

Fix error handling in lookup_invoice.

The function still uses .unwrap() at line 74 which can cause runtime panics. This was previously reported and should be fixed with proper error handling.

pub async fn lookup_invoice(
    &self,
    payment_hash: String,
) -> Result<crate::Transaction, ApiError> {
    let transactions = crate::cln::api::lookup_invoice(
        self.url.clone(),
        self.rune.clone(),
        Some(payment_hash),
        None,
        None,
    )
-    .unwrap();
+    .map_err(|e| ApiError::Http { reason: format!("Failed to lookup invoice: {}", e) })?;
    transactions.into_iter().next().ok_or(ApiError::Json {
        reason: "No transactions found".to_string(),
    })
}
crates/lni/cln/api.rs (4)

135-167: ⚠️ Potential issue

Use async client for async function and improve error handling in pay_offer.

The function is marked as async but uses blocking HTTP methods. Additionally, all .unwrap() calls should be replaced with proper error handling.

pub async fn pay_offer(
    url: String,
    rune: String,
    offer: String,
    amount_msats: i64,
    payer_note: Option<String>,
) -> Result<PayInvoiceResponse, ApiError> {
    let fetch_invoice_url = format!("{}/v1/fetchinvoice", url);
-    let client = clnrest_client(rune);
+    let client = clnrest_async_client(rune).await?;
-    let response: reqwest::blocking::Response = client
+    let response = client
        .post(&fetch_invoice_url)
        .header("Content-Type", "application/json")
        .json(&serde_json::json!({
            "offer": offer,
            "amount_msat": amount_msats,
            "payer_note": payer_note,
            "timeout": 60,
        }))
        .send()
-        .unwrap();
-    let response_text = response.text().unwrap();
-    let response_text = response_text.as_str();
+        .await.map_err(|e| ApiError::Http { reason: e.to_string() })?;
+    let response_text = response.text()
+        .await
+        .map_err(|e| ApiError::Http { reason: e.to_string() })?;
    let fetch_invoice_resp: FetchInvoiceResponse = match serde_json::from_str(&response_text) {
        Ok(resp) => {
-            println!("fetch_invoice_resp: {:?}", resp);
+            log::debug!("fetch_invoice_resp: {:?}", resp);
            resp
        }

You'll also need to implement an async version of the client builder:

async fn clnrest_async_client(rune: String) -> Result<reqwest::Client, ApiError> {
    let mut headers = reqwest::header::HeaderMap::new();
    headers.insert(
        "Rune", 
        header::HeaderValue::from_str(&rune)
            .map_err(|e| ApiError::Http { reason: e.to_string() })?
    );
    
    reqwest::ClientBuilder::new()
        .danger_accept_invalid_certs(true) // Consider making this configurable
        .default_headers(headers)
        .build()
        .map_err(|e| ApiError::Http { reason: e.to_string() })
}

175-196: ⚠️ Potential issue

Use async methods and proper error handling for payment request.

Similar to the fetch invoice request, this code needs to use async methods and proper error handling to avoid unwraps.

// now pay the bolt 12 invoice lni
let pay_url = format!("{}/v1/pay", url);
-let pay_response: reqwest::blocking::Response = client
+let pay_response = client
    .post(&pay_url)
    .header("Content-Type", "application/json")
    .json(&serde_json::json!({
        "bolt11": fetch_invoice_resp.invoice.to_string(),
-        "maxfeepercent": 1, // TODO read from config
+        "maxfeepercent": 1, // TODO: Make this configurable
        "retry_for": 60,
    }))
    .send()
-    .unwrap();
-let pay_response_text = pay_response.text().unwrap();
-let pay_response_text = pay_response_text.as_str();
+    .await
+    .map_err(|e| ApiError::Http { reason: e.to_string() })?;
+let pay_response_text = pay_response.text()
+    .await
+    .map_err(|e| ApiError::Http { reason: e.to_string() })?;
let pay_resp: PayResponse = match serde_json::from_str(&pay_response_text) {
    Ok(resp) => resp,
    Err(e) => {
+        log::error!("Failed to parse pay response: {:?}", e);
        return Err(ApiError::Json {
            reason: pay_response_text.to_string(),
        })
    }
};

230-242: ⚠️ Potential issue

Improve error handling in HTTP request and remove commented-out code.

The HTTP request uses .unwrap() which can cause runtime panics. Also, there's commented code that should be removed.

// Fetch incoming transactions
let response: reqwest::blocking::Response = client
    .post(&list_invoices_url)
    .header("Content-Type", "application/json")
-    //.json(&serde_json::json!(params))
    .json(&serde_json::json!(params
        .into_iter()
        .filter_map(|(k, v)| v.map(|v| (k, v)))
        .collect::<serde_json::Value>()))
    .send()
-    .unwrap();
-let response_text = response.text().unwrap();
-let response_text = response_text.as_str();
-let incoming_payments: InvoicesResponse = serde_json::from_str(&response_text).unwrap();
+    .map_err(|e| ApiError::Http { reason: e.to_string() })?;
+let response_text = response.text()
+    .map_err(|e| ApiError::Http { reason: e.to_string() })?;
+let incoming_payments: InvoicesResponse = serde_json::from_str(&response_text)
+    .map_err(|e| ApiError::Json { reason: e.to_string() })?;

256-257: ⚠️ Potential issue

Implement the created_at field.

The created_at field is set to 0 with a TODO comment. This should be properly implemented to ensure transactions are sorted correctly.

-    created_at: 0, // TODO
+    created_at: inv.paid_at.unwrap_or_else(|| inv.expires_at - (expiry.unwrap_or(3600) as u64)),

The suggested implementation attempts to calculate a creation time based on either the payment time or by subtracting the expiry period from the expiration time.

🧹 Nitpick comments (7)
crates/lni/cln/types.rs (2)

31-36: Use more descriptive field name for outnum

The field outnum in PaidOutpoint struct is not immediately clear in its purpose. Consider using a more descriptive name like output_index or vout to better reflect that this is a transaction output index.


40-58: Add more specific status type enumeration for invoices

The comment on line 44 indicates that status can have values like "paid", "unpaid", or "expired". Consider defining an enum for this field rather than using a String to enforce valid status values at compile time.

+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum InvoiceStatus {
+    Paid,
+    Unpaid,
+    Expired,
+}

 #[derive(Debug, Deserialize)]
 pub struct Invoice {
     pub label: String,
     pub bolt11: Option<String>,
     pub bolt12: Option<String>,
     pub payment_hash: String,
-    pub status: String, // "paid" "unpaid" "expired"
+    pub status: InvoiceStatus,
     pub pay_index: Option<i32>,
     // Other fields remain unchanged
readme.md (1)

107-113: Improved troubleshooting instructions for React Native

The expanded troubleshooting section provides valuable steps for resolving common React Native integration issues, making it easier for developers to work with the library.

However, there's a typo in "react-natve" that should be corrected to "react-native".

-`*troubleshooting react-natve`: 
+`*troubleshooting react-native`: 
🧰 Tools
🪛 LanguageTool

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~109-~109: This phrase is duplicated. You should probably use “for ios” only once.
Context: ...swipe away app) - try updating the pods for ios cd example/ios && pod install --repo-update && cd ../ - for ios open the xcode app - lni/bindings/lni_r...

(PHRASE_REPETITION)

🪛 markdownlint-cli2 (0.17.2)

111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

bindings/lni_nodejs/src/cln.rs (3)

42-59: Review parameter cloning in create_invoice method

The create_invoice method clones the URL and rune for each API call. Consider passing references instead of cloning these values, especially if they might be large strings.

 let txn = lni::cln::api::create_invoice(
-  self.inner.url.clone(),
-  self.inner.rune.clone(),
+  &self.inner.url,
+  &self.inner.rune,
   params.invoice_type,
   params.amount_msats,
   params.description,
   params.description_hash,
   params.expiry,
 )

This would require updating the signature of the underlying API function to accept string references instead of owned strings.


74-90: pay_offer method has inconsistent formatting

There's inconsistent formatting in the pay_offer method. The closing parenthesis for the pay_offer call is followed by .await on the next line.

 let offer = lni::cln::api::pay_offer(
   self.inner.url.clone(),
   self.inner.rune.clone(),
   offer,
   amount_msats,
   payer_note,
-).await
+)
+.await
 .map_err(|e| napi::Error::from_reason(e.to_string()))?;

108-145: Remove or update commented test code

There's a large block of commented-out test code. This should either be updated to test CLN functionality and uncommented, or removed if it's no longer needed. Commented test code can become outdated and confusing.

If this test code was for PhoenixdNode (as indicated by the variable names), it should be updated to test ClnNode functionality:

// #[cfg(test)]
// mod tests {
//   use super::*;
//   use dotenv::dotenv;
//   use lazy_static::lazy_static;
//   use std::env;
//   use tokio::test;
//
//   lazy_static! {
//     static ref URL: String = {
//       dotenv().ok();
//       env::var("CLN_URL").expect("CLN_URL must be set")
//     };
//     static ref RUNE: String = {
//       dotenv().ok();
//       env::var("CLN_RUNE").expect("CLN_RUNE must be set")
//     };
//     static ref NODE: ClnNode = {
//       ClnNode::new(ClnConfig {
//         url: URL.clone(),
//         rune: RUNE.clone(),
//       })
//     };
//   }
//
//   #[test]
//   async fn test_get_info() {
//     match NODE.get_info().await {
//       Ok(info) => {
//         println!("info: {:?}", info.pubkey);
//         assert!(!info.pubkey.is_empty(), "Node pubkey should not be empty");
//       }
//       Err(e) => {
//         panic!("Failed to get info: {:?}", e);
//       }
//     }
//   }
// }
crates/lni/cln/lib.rs (1)

137-138: Improve error message in get_info test.

The panic message at line 137 says "Failed to get offer" but it should be "Failed to get node info".

-                panic!("Failed to get offer: {:?}", e);
+                panic!("Failed to get node info: {:?}", e);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fa7f51 and e830c45.

📒 Files selected for processing (17)
  • bindings/lni_nodejs/index.d.ts (5 hunks)
  • bindings/lni_nodejs/index.js (1 hunks)
  • bindings/lni_nodejs/main.mjs (1 hunks)
  • bindings/lni_nodejs/src/cln.rs (1 hunks)
  • bindings/lni_nodejs/src/phoenixd.rs (3 hunks)
  • bindings/lni_react_native/example/src/App.tsx (5 hunks)
  • bindings/lni_uniffi/src/lni.udl (5 hunks)
  • crates/lni/Cargo.toml (1 hunks)
  • crates/lni/cln/api.rs (1 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/cln/types.rs (1 hunks)
  • crates/lni/lib.rs (1 hunks)
  • crates/lni/phoenixd/api.rs (12 hunks)
  • crates/lni/phoenixd/lib.rs (7 hunks)
  • crates/lni/phoenixd/types.rs (1 hunks)
  • crates/lni/types.rs (3 hunks)
  • readme.md (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • bindings/lni_nodejs/index.js
  • bindings/lni_react_native/example/src/App.tsx
  • bindings/lni_nodejs/index.d.ts
🧰 Additional context used
🪛 LanguageTool
readme.md

[uncategorized] ~107-~107: Loose punctuation mark.
Context: ...tart ``` *troubleshooting react-natve: - if you get an error like `uniffiEnsu...

(UNLIKELY_OPENING_PUNCTUATION)


[grammar] ~109-~109: This phrase is duplicated. You should probably use “for ios” only once.
Context: ...swipe away app) - try updating the pods for ios cd example/ios && pod install --repo-update && cd ../ - for ios open the xcode app - lni/bindings/lni_r...

(PHRASE_REPETITION)


[uncategorized] ~147-~147: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~147-~147: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)


[grammar] ~261-~261: It appears that a hyphen is missing in the noun “To-do” (= task) or did you mean the verb “to do”?
Context: ...-->>App: PayInvoiceResponse object ``` Todo ==== - [X] make interface - [X] napi-rs...

(TO_DO_HYPHEN)


[uncategorized] ~265-~265: The official spelling of this programming framework is “Node.js”.
Context: ... - [X] make interface - [X] napi-rs for nodejs - [X] uniffi bindings for Android and I...

(NODE_JS)

🪛 markdownlint-cli2 (0.17.2)
readme.md

111-111: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


124-124: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


124-124: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


125-125: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


144-144: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


145-145: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


148-148: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


278-278: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


283-283: Bare URL used
null

(MD034, no-bare-urls)


286-286: Bare URL used
null

(MD034, no-bare-urls)

🔇 Additional comments (41)
crates/lni/Cargo.toml (1)

28-28: Good addition of the rand crate.

Adding the rand crate (version 0.8) is appropriate for the implementation of ClnNode, as it will likely be used for generating random values needed in cryptographic operations common in Lightning Network implementations.

crates/lni/lib.rs (2)

26-28: Well-structured module organization.

Good refactoring of the phoenixd module to include a dedicated types submodule and cleaner exports.


30-35: Good implementation of the cln module.

The structure of the cln module mirrors the phoenixd module, which maintains consistency in the codebase. The exports correctly include ClnConfig and ClnNode from the lib submodule.

bindings/lni_nodejs/main.mjs (2)

5-42: Good refactoring of phoenixd functionality.

The phoenixd functionality has been properly encapsulated in its own function with clear steps for configuration, node information retrieval, invoice creation, and transaction listing.


44-87: Well-implemented cln functionality.

The cln function follows the same pattern as phoenixd, providing consistent behavior between both implementations. The code correctly utilizes environment variables for configuration.

crates/lni/types.rs (4)

45-46: Good addition of optional fields for transaction details.

Adding payer_note and external_id as optional fields enhances the Transaction struct with better support for both bolt12 and bolt11 formats.


174-174: Critical payment_hash field added to PayInvoiceResponse.

Adding the payment_hash field to PayInvoiceResponse is essential as it provides a unique identifier for payments in the Lightning Network.


203-209: Well-designed ListTransactionsParams struct.

The ListTransactionsParams struct provides a clean interface for pagination and filtering of transactions with sensible default fields.


212-220: Flexible CreateInvoiceParams struct.

The CreateInvoiceParams struct is well-designed with appropriate optional fields that provide flexibility in invoice creation for different use cases.

crates/lni/phoenixd/lib.rs (4)

35-48: Function rename: make_invoicecreate_invoice

The function has been renamed from make_invoice to create_invoice with a parameter type change from PhoenixdMakeInvoiceParams to CreateInvoiceParams. This API change appears to be part of a broader standardization across the codebase.

When deploying, ensure all calling code has been updated to use the new function name.


74-85: Simplified list_transactions parameters

The list_transactions implementation now passes None for the omitted parameters, which simplifies the API. This change aligns with the modified function signature in the API module.


136-177: Test updated to reflect API changes

The test function has been properly updated to use the new create_invoice method name and the new CreateInvoiceParams structure, with both Bolt11 and Bolt12 test cases covered.


117-120:

✅ Verification successful

Environment variable renamed: TEST_OFFER → TEST_RECEIVER_OFFER

The static reference and environment variable have been renamed from TEST_OFFER to TEST_RECEIVER_OFFER. Make sure this environment variable is updated in all deployment environments.


🏁 Script executed:

#!/bin/bash
# Check if any references to the old environment variable name still exist
rg "TEST_OFFER" --type rust

Length of output: 27


I'm generating an additional verification script to search the entire repository for any lingering references to the old environment variable. This will help ensure that "TEST_OFFER" isn’t accidentally present in non‑Rust files (e.g., configuration or deployment scripts).

Please run this script and verify its output. Based on the result, if no references are found, the renaming from TEST_OFFER to TEST_RECEIVER_OFFER appears consistent. If any instances are found, further investigation into those files will be needed to complete the renaming process.


🏁 Script executed:

#!/bin/bash
# Search the entire repository (all file types) for references to the old environment variable name "TEST_OFFER"
rg "TEST_OFFER"

Length of output: 15


Environment variable renaming verified – please confirm deployment configs

The code changes (in crates/lni/phoenixd/lib.rs at lines 117–120) correctly update the static reference to use TEST_RECEIVER_OFFER, and our repository scans show no remaining references to the old name (TEST_OFFER). Please ensure that all deployment and CI/CD configurations are updated to use the new environment variable name.

bindings/lni_nodejs/src/phoenixd.rs (3)

1-1: Updated import for new parameter structure

The import has been updated to use CreateInvoiceParams which aligns with the changes in the core Rust implementation.


42-59: Node.js binding updated to match Rust API changes

The Node.js binding function has been renamed from make_invoice to create_invoice and updated to use the new parameter structure. This ensures consistency between the Rust implementation and the Node.js bindings.


91-100: Simplified list_transactions parameters in Node.js binding

The list_transactions method has been updated to use crate::ListTransactionsParams and now passes None for the omitted parameter, which aligns with the changes in the core Rust implementation.

crates/lni/phoenixd/types.rs (1)

1-101: New types module with well-structured data models

This new file introduces several well-structured data models with proper serialization/deserialization mappings between Rust and JSON field names. The structs follow a consistent pattern and provide clear field documentation where needed (e.g., which fields are used in Bolt11 vs. Bolt12 scenarios).

Some observations:

  • All structs properly derive Debug for improved logging
  • JSON field names are correctly mapped using serde attributes
  • Types that need to be exposed to Node.js are properly annotated with the napi macro

This is a good refactoring that improves code organization by moving types to their own module.

crates/lni/phoenixd/api.rs (6)

1-4: Updated imports to use new types module

The imports now reference the types from the newly created types.rs module, which improves code organization.


32-40: Function rename: make_invoicecreate_invoice with optional amount

The function has been renamed from make_invoice to create_invoice and the amount_msats parameter has been changed from a required i64 to an Option<i64>. This change allows the function to handle cases where the amount is not specified, like for Bolt12 invoices.


48-48: Safe handling of optional amount_msats

The code now uses unwrap_or_default() to ensure that amount_sat is set to zero if amount_msats is None. This change makes the code more robust by handling optional values properly.


77-85: Added payer_note and external_id fields to Transaction struct

New fields have been added to the Transaction struct to support additional metadata for transactions.


140-144: Added payment_hash to PayInvoiceResponse

The payment_hash field has now been included in the PayInvoiceResponse struct, ensuring that this critical identifier is available for tracking payments.


171-172: Properly unwrapping optional payer_note and external_id

The code now correctly unwraps the optional payer_note and external_id fields from the invoice response, defaulting to empty strings if they're not present.

crates/lni/cln/types.rs (3)

5-6: Remove or implement the commented code for node_id field

The commented-out lines for the node_id field should either be implemented if needed or removed to maintain clean code.


19-29: Consider using unsigned integers for payment amounts

The fields amount_msat and amount_sent_msat are using signed integers (i64), but payment amounts are inherently non-negative values. Consider using u64 instead for better type safety.


75-83:

❓ Verification inconclusive

Ensure Bolt12Resp fields have correct types

Several boolean fields in Bolt12Resp (active, single_use, used, created) may need validation to ensure they are properly deserialized from the API response. Verify the API documentation to confirm these are indeed boolean fields and not strings or integers representing true/false values.


🏁 Script executed:

#!/bin/bash
# Check CLN API documentation or code references for Bolt12 response fields
rg -A 3 -B 3 "active|single_use|used|created" --type rust crates/lni/cln/

Length of output: 3810


Double-check BOlt12Resp API boolean types

The Bolt12Resp structure in crates/lni/cln/types.rs correctly declares the fields active, single_use, used, and created as booleans. Our search confirms that there’s no evidence of custom conversion logic or mismatches elsewhere in the codebase. However, please verify using the official CLN API documentation that these fields are indeed expected to be received as booleans rather than alternative representations (e.g., numeric or string values).

  • File to review: crates/lni/cln/types.rs (struct Bolt12Resp)
bindings/lni_uniffi/src/lni.udl (5)

9-10: Method signature updated to use consistent naming

The method was renamed from make_invoice to create_invoice and now uses the more generic CreateInvoiceParams type, improving consistency across the codebase.


65-71: Good improvement: Added optional amount parameter

Making the amount_msats field optional in CreateInvoiceParams is a good improvement as it allows for creating invoices without specifying an amount, which is useful for donation-type invoices.


99-100: Added helpful fields to Transaction dictionary

Adding payer_note and external_id fields to the Transaction dictionary enhances the data model by providing additional context for transactions, which is useful for user-facing applications.


199-200: Added essential payment_hash field to PayInvoiceResponse

Adding the payment_hash field to PayInvoiceResponse is crucial as it provides a unique identifier for the payment, enabling proper tracking and reconciliation.


223-227: Simplified ListTransactionsParams with focused filtering

The ListTransactionsParams dictionary has been simplified to include only from, limit, and an optional payment_hash, removing less used fields and focusing on the most common filtering needs.

readme.md (6)

124-136: Updated environment variables with new CLN configuration

The environment variables section has been correctly updated to replace TEST_OFFER with more specific variables like TEST_RECEIVER_OFFER and PHOENIX_MOBILE_OFFER, and to add new CLN-specific variables. This change improves configuration clarity.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

124-124: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)


124-124: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)


125-125: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


144-144: Improved build command for Node.js bindings

The updated build command includes cleaning the cargo build cache and building in release mode, which should result in better performance for the final bindings.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

144-144: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


147-160: Added guidance for native Node.js module integration

The new section on using native Node.js modules provides valuable information for developers who want to integrate the library with Electron or other native Node.js applications.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~147-~147: The official spelling of this programming framework is “Node.js”.
Context: ...rn build - testnode main.mjs` - nodejs - native modules (electron, vercel etc....

(NODE_JS)


[typographical] ~147-~147: Two consecutive dots
Context: ...s - native modules (electron, vercel etc..) - if you want to use the native no...

(DOUBLE_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

148-148: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


211-260: Added helpful sequence diagram

The sequence diagram is an excellent addition that visualizes the interactions between different components of the system, making it easier for developers to understand the architecture.


269-279: Updated implementation status in todo list

The todo list has been updated to reflect the current implementation status, including marking CLN as completed and adding new potential implementations (lndk, ldk_node, strike, nwc).

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

271-271: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


272-272: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


273-273: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


274-274: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


275-275: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


276-276: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


277-277: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


278-278: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


285-286: Added new research item for REST API facade

Adding the research item for a facade REST API that uses the same API as Phoenixd is a good idea for future development, as it would standardize the API across different lightning node implementations.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

286-286: Bare URL used
null

(MD034, no-bare-urls)

bindings/lni_nodejs/src/cln.rs (3)

1-8: Well-structured CLN Node implementation

The ClnNode struct is well-designed with a clean separation of concerns, storing the configuration in an inner field.


17-33: Appropriate accessor methods for configuration

The accessor methods for URL, rune, and full configuration are implemented correctly and provide the necessary functionality for interacting with the node configuration.


35-40: Well-implemented get_info method with proper error handling

The get_info method correctly handles error cases by mapping API errors to NAPI errors with descriptive messages.

crates/lni/cln/lib.rs (1)

113-116: Missing environment variable in README.

The test uses PHOENIX_MOBILE_OFFER environment variable, but this isn't documented in the README.

Please add the PHOENIX_MOBILE_OFFER environment variable to the .env section in the README to ensure developers can run the tests successfully.

#!/bin/bash
# Verify if PHOENIX_MOBILE_OFFER is documented in README.md
grep -i "PHOENIX_MOBILE_OFFER" README.md || echo "PHOENIX_MOBILE_OFFER is not documented in README.md"

Comment on lines +181 to +187
// until: i64,
limit: i64,
offset: i64,
unpaid: bool,
invoice_type: String, // not currently used but included for parity
payment_hash: Option<String>,
// offset: i64,
// unpaid: bool,
// invoice_type: Option<String>, // not currently used but included for parity
// search_term: Option<String>, // not currently used but included for parity
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Simplified list_transactions parameters

Several parameters have been commented out in the list_transactions function signature, indicating a simplification of the API. Make sure all callers have been updated to use the new simplified signature.


🏁 Script executed:

#!/bin/bash
# Check for any callers of list_transactions that might be passing the now-removed parameters
rg "list_transactions.*until|offset|unpaid|invoice_type" --type rust

Length of output: 1510


Action: Update all call sites for list_transactions to match the simplified signature

The new signature in crates/lni/phoenixd/api.rs now only accepts limit: i64 and payment_hash: Option<String>—the other parameters (until, offset, unpaid, and invoice_type) have been commented out. However, the verification search revealed that several modules are still referencing invoice_type (and related fields), for example:

  • crates/lni/phoenixd/lib.rs – several call sites still pass params.invoice_type.
  • crates/lni/cln/lib.rs & crates/lni/cln/api.rs – similar references to params.invoice_type remain.
  • NodeJS bindings (bindings/lni_nodejs/src/phoenixd.rs and bindings/lni_nodejs/src/cln.rs) – these also continue referencing params.invoice_type.

Please update these callers to align with the simplified signature. Additionally, once all call sites are updated, consider removing the commented-out code from the API definition to avoid confusion.

Comment on lines 61 to 72
#[napi]
pub async fn lookup_invoice(&self, payment_hash: String) -> napi::Result<lni::Transaction> {
let txn = lni::cln::api::lookup_invoice(
self.inner.url.clone(),
self.inner.rune.clone(),
Some(payment_hash),
None,
None,
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason("No transaction found"))?)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Potential issue with error handling in lookup_invoice

The error handling in lookup_invoice method could be improved. The current implementation uses .into_iter().next() and then ok_or_else to handle the case when no transaction is found, but this might not provide a clear error message about what went wrong.

Consider making the error message more descriptive by including the payment hash:

-Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason("No transaction found"))?)
+Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason(format!("No transaction found for payment hash: {}", payment_hash)))?)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[napi]
pub async fn lookup_invoice(&self, payment_hash: String) -> napi::Result<lni::Transaction> {
let txn = lni::cln::api::lookup_invoice(
self.inner.url.clone(),
self.inner.rune.clone(),
Some(payment_hash),
None,
None,
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason("No transaction found"))?)
}
#[napi]
pub async fn lookup_invoice(&self, payment_hash: String) -> napi::Result<lni::Transaction> {
let txn = lni::cln::api::lookup_invoice(
self.inner.url.clone(),
self.inner.rune.clone(),
Some(payment_hash),
None,
None,
)
.map_err(|e| napi::Error::from_reason(e.to_string()))?;
Ok(txn.into_iter().next().ok_or_else(|| napi::Error::from_reason(format!("No transaction found for payment hash: {}", payment_hash)))?)
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
bindings/lni_nodejs/main.mjs (1)

96-101: ⚠️ Potential issue

Add proper promise handling in main function

The main function calls phoenixd and cln without awaiting them, which means their promises won't be handled properly and errors could be silently ignored.

async function main() {
-  phoenixd();
-  cln();
+  try {
+    await phoenixd();
+    await cln();
+  } catch (error) {
+    console.error("Error in execution:", error);
+    process.exit(1);
+  }
}
crates/lni/phoenixd/api.rs (1)

258-262: ⚠️ Potential issue

Critical: Inconsistent Handling of the description Field

The current implementation in list_transactions (line 258) still hard-codes the description as an empty string, which deviates from the pattern observed elsewhere where the field is set from the invoice using unwrap_or_default().

-                description: "".to_string(),
+                description: inv.description.unwrap_or_default(),
bindings/lni_nodejs/src/cln.rs (1)

115-128: ⚠️ Potential issue

Pass the optional payment_hash to list_transactions.

Calls to lni::cln::api::list_transactions do not include params.payment_hash, causing potential mismatches with user expectations:

 let txns = lni::cln::api::list_transactions(
   self.inner.url.clone(),
   self.inner.rune.clone(),
   params.from,
   params.limit,
+  params.payment_hash, // Add this to filter transactions if provided
 )
crates/lni/cln/lib.rs (2)

74-85: ⚠️ Potential issue

Avoid using .unwrap() for error handling in lookup_invoice.

This can cause a runtime panic if the underlying call fails. Consider a safe error transformation:

- .unwrap();
+ .map_err(|e| ApiError::Http {
+   reason: format!("Failed to lookup invoice: {}", e)
+ })?;

91-102: ⚠️ Potential issue

Use list_transactions instead of lookup_invoice for listing.

This block calls crate::cln::api::lookup_invoice but should call list_transactions with params:

- crate::cln::api::lookup_invoice(
+ crate::cln::api::list_transactions(
   self.url.clone(),
   self.rune.clone(),
   None,
   Some(params.from),
   Some(params.limit),
)
🧹 Nitpick comments (6)
bindings/lni_uniffi/src/lni.udl (4)

3-6: Consider clarifying usage and scope for PhoenixdConfig.

Documenting in-code or in the broader docs how url and password should be used or secured (e.g. handling credentials securely) could help developers integrate it more confidently.


17-18: Check the naming consistency for get_offer.

As the parameter name is omitted, consider providing clarity (e.g. get_offer(search: string?)) in the documentation or comments for future maintainers.


102-105: Optional values in CreateInvoiceParams seem flexible.

Confirm that all downstream consumers (e.g. create_invoice calls) properly handle amount_msats == null or offer == null.


267-273: PayCode dictionary addition is aligned with BOLT12-based flows.

Consider whether an optional expires_at or additional metadata might be helpful for advanced client handling, if relevant to your application logic.

bindings/lni_nodejs/src/cln.rs (1)

98-113: Incorporate the payment hash in “No transaction found” error.

Including the user-supplied hash in the error message helps debugging. For example:

- .ok_or_else(|| napi::Error::from_reason("No transaction found"))?
+ .ok_or_else(|| napi::Error::from_reason(
+   format!("No transaction found for payment hash: {}", payment_hash)
+ ))?
crates/lni/cln/api.rs (1)

148-166: Consider removing unwrap() usage in get_offer.
Although it’s logically safe due to the preceding empty-check on offers, calling unwrap() can still be confusing to readers. As a minor improvement, consider using safe Rust idioms (e.g., offers.first().cloned().unwrap_or_default()) to avoid potential surprise.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e830c45 and 338519a.

📒 Files selected for processing (13)
  • bindings/lni_nodejs/index.d.ts (5 hunks)
  • bindings/lni_nodejs/main.mjs (1 hunks)
  • bindings/lni_nodejs/src/cln.rs (1 hunks)
  • bindings/lni_nodejs/src/database.rs (0 hunks)
  • bindings/lni_nodejs/src/phoenixd.rs (4 hunks)
  • bindings/lni_uniffi/src/lib.rs (1 hunks)
  • bindings/lni_uniffi/src/lni.udl (6 hunks)
  • crates/lni/cln/api.rs (1 hunks)
  • crates/lni/cln/lib.rs (1 hunks)
  • crates/lni/cln/types.rs (1 hunks)
  • crates/lni/phoenixd/api.rs (11 hunks)
  • crates/lni/phoenixd/lib.rs (7 hunks)
  • crates/lni/types.rs (4 hunks)
💤 Files with no reviewable changes (1)
  • bindings/lni_nodejs/src/database.rs
🧰 Additional context used
🧬 Code Definitions (4)
bindings/lni_nodejs/src/phoenixd.rs (3)
bindings/lni_nodejs/index.d.ts (4) (4)
  • CreateInvoiceParams (163-170)
  • Transaction (43-57)
  • PayCode (171-178)
  • ListTransactionsParams (158-162)
crates/lni/phoenixd/lib.rs (3) (3)
  • create_invoice (32-46)
  • get_offer (48-50)
  • list_transactions (75-86)
crates/lni/phoenixd/api.rs (3) (3)
  • create_invoice (34-96)
  • get_offer (107-124)
  • list_transactions (195-324)
crates/lni/types.rs (1)
bindings/lni_nodejs/index.d.ts (3) (3)
  • ListTransactionsParams (158-162)
  • CreateInvoiceParams (163-170)
  • PayCode (171-178)
crates/lni/cln/types.rs (1)
bindings/lni_nodejs/index.d.ts (2) (2)
  • PayCode (171-178)
  • Bolt11Resp (14-18)
crates/lni/cln/lib.rs (2)
bindings/lni_nodejs/index.d.ts (8) (8)
  • NodeInfo (35-42)
  • CreateInvoiceParams (163-170)
  • ListTransactionsParams (158-162)
  • PayCode (171-178)
  • PayInvoiceResponse (142-146)
  • Transaction (43-57)
  • ClnConfig (19-22)
  • ClnNode (23-26)
bindings/lni_nodejs/src/cln.rs (9) (9)
  • new (12-14)
  • get_info (35-39)
  • create_invoice (42-59)
  • get_offer (62-67)
  • list_offers (70-76)
  • pay_offer (79-95)
  • lookup_invoice (98-113)
  • list_transactions (116-128)
  • decode (131-136)
🔇 Additional comments (59)
bindings/lni_uniffi/src/lib.rs (1)

2-4: Library exports updated to include new CLN module

The changes to the public use statements correctly expose the CLN module while maintaining the existing phoenixd module. This aligns with the Core Lightning integration that's being implemented.

bindings/lni_nodejs/index.d.ts (7)

19-26: CLN configuration and node interfaces added correctly

The new interfaces for Core Lightning are properly defined with the required URL and rune properties, which are the standard authentication mechanism for CLN REST API.


55-57: Fields added to Transaction interface

The optional payerNote and externalId fields enhance the Transaction interface to support additional metadata, which is useful for providing context to payments.


158-162: ListTransactionsParams interface simplified

The interface has been simplified to focus on pagination parameters and an optional payment hash filter, making it more targeted and easier to use.


163-170: CreateInvoiceParams interface provides flexible invoice creation

This new interface supports both BOLT11 and BOLT12 invoice types with appropriate optional parameters, allowing for future extensibility.


171-178: PayCode interface added for offer support

The PayCode interface properly models Lightning Network offers (BOLT12), including important metadata like single use status and activation.


193-197: PhoenixdNode API updated to use consistent naming

The method was renamed from makeInvoice to createInvoice for better API consistency across node implementations.


199-212: ClnNode class implemented with comprehensive API

The new ClnNode class implements all core Lightning functionality including node info, invoice creation, offer management, and transaction listing. The additional decode method is a nice enhancement for working with Lightning encoded strings.

crates/lni/phoenixd/lib.rs (9)

4-6: Imports updated to use shared types

The import statements have been updated to use the common types from the crate root, which improves code organization by centralizing type definitions.


32-46: Method renamed and updated to use common parameter type

The make_invoice method has been renamed to create_invoice and updated to use the shared CreateInvoiceParams type. The default value handling for amount_msats is also improved.


48-50: Added new method to retrieve Lightning offers

The new get_offer method allows retrieving BOLT12 offers, which is a valuable addition for supporting the latest Lightning Network capabilities.


75-86: Updated list_transactions to use simpler parameters

The method now uses the simplified ListTransactionsParams structure and passes None for omitted parameters, maintaining backward compatibility while streamlining the API.


118-121: Environment variable reference updated

The static reference has been renamed from TEST_OFFER to TEST_RECEIVER_OFFER to more accurately describe its purpose, and the corresponding environment variable accessed has been updated.


138-161: Test updated to use new parameter structure

The test has been updated to use the new CreateInvoiceParams structure, ensuring that tests remain valid with the API changes.


163-175: New test added for get_offer functionality

A new test has been added to verify the get_offer functionality, which is important for ensuring the new method works correctly.


178-194: Updated test for paying offers

The test has been updated to use the new environment variable name TEST_RECEIVER_OFFER and includes a note parameter, ensuring comprehensive testing of the payment functionality.


197-213: Test for list_transactions updated to use new parameters

The test has been updated to use the simplified ListTransactionsParams structure, maintaining test coverage for the updated API.

bindings/lni_nodejs/main.mjs (2)

1-45: Phoenixd functionality extracted to dedicated function

The phoenixd-related code has been refactored into a separate async function, which improves code organization. The implementation correctly uses the updated API methods like createInvoice and includes the new getOffer functionality.


47-94: New CLN functionality added in dedicated function

The new CLN implementation is properly structured in its own async function with equivalent functionality to the phoenixd implementation. The commented-out code regarding CLN-to-phoenixd payment issues is appropriately documented with a TODO.

crates/lni/phoenixd/api.rs (10)

34-42: Function renamed from make_invoice to create_invoice with updated parameters

The function signature has been updated to use a more descriptive name and now accepts amount_msats as an Option<i64> instead of a required i64, making it more flexible.


48-54: Good handling of optional amount parameter

The code properly handles the optional amount_msats parameter using unwrap_or_default(), which will set amount_sat to 0 if amount_msats is None.


79-88: Updated transaction creation with new optional fields

The transaction creation now includes initialization of the new payer_note and external_id fields, which aligns with the updated Transaction struct.


90-94: Improved error message for unsupported bolt12 invoices

The error message is now more specific about what functionality isn't supported.


98-124: New functions for BOLT12 support and offer handling

The introduction of decode and get_offer functions adds support for BOLT12 functionality, although the decode function is currently just a placeholder.


149-153: Improved error handling in pay_offer function

The error handling now properly returns the raw response text in error cases, making debugging easier.


155-159: Added payment_hash to PayInvoiceResponse

The function now includes payment_hash in the response, which is important for tracking and referencing payments.


189-190: Added support for payer_note and external_id in lookup_invoice

These fields are now properly extracted from the invoice response and included in the transaction.


199-205: Simplified list_transactions parameters

Several parameters have been commented out, simplifying the API. Make sure all call sites have been updated to use the new simplified signature.

#!/bin/bash
# Check for any callers of list_transactions that might be passing the now-removed parameters
rg "list_transactions.*until|offset|unpaid|invoice_type" --type rust

313-316: Consistent handling of payer_note and external_id

The outgoing transactions now properly include the payer_note and external_id fields, consistent with the handling for incoming transactions.

bindings/lni_nodejs/src/phoenixd.rs (5)

1-1: Updated import to use CreateInvoiceParams

The import now correctly references the new CreateInvoiceParams type from the lni crate.


43-59: Function renamed from make_invoice to create_invoice

The function has been renamed to create_invoice to match the API changes, and now correctly uses the new CreateInvoiceParams type.


61-67: Added get_offer function

New function added to retrieve BOLT12 offers via the API, aligning with the new functionality in the backend.


93-95: Fixed ordering of await and error mapping

The code now correctly awaits the result before mapping the error, ensuring proper asynchronous error handling.


102-110:

✅ Verification successful

Updated list_transactions parameters

The function now correctly uses the simplified parameter type and passes None for parameters that have been removed from the API. This aligns with the changes in the API function.


🏁 Script executed:

#!/bin/bash
# Check if the ListTransactionsParams struct in the codebase matches this usage
rg "struct ListTransactionsParams" --type rust -A 10

Length of output: 581


Verified: The updated parameters match the API changes.
The lni::phoenixd::api::list_transactions call now correctly uses params.from and params.limit while explicitly passing None for the removed parameter. Although the ListTransactionsParams struct still contains payment_hash, the omission of its value in the API call is intentional and aligns with the simplified parameter usage.

crates/lni/types.rs (4)

3-3: Added Serialize trait to imports

The import now includes both Serialize and Deserialize traits from serde, enabling serialization for the defined types.


45-46: Added new fields to Transaction struct

The Transaction struct now includes optional payer_note and external_id fields, enabling better support for BOLT12 payments and external references.


174-174: Added payment_hash to PayInvoiceResponse

The PayInvoiceResponse struct now includes a required payment_hash field, improving payment tracking capabilities.


203-232: Added new parameter and response structures

Three new structs have been added:

  1. ListTransactionsParams - For simplified transaction listing parameters
  2. CreateInvoiceParams - For invoice creation with flexible parameters
  3. PayCode - For BOLT12 offer representation

These additions support the API changes and provide proper type safety for the new functionality.

crates/lni/cln/types.rs (6)

1-4: New file for Core Lightning type definitions

This file defines the necessary types for Core Lightning (CLN) integration, properly importing required dependencies.


5-14: Remove unused commented code for node_id field

The commented-out lines for the node_id field are not used elsewhere in the codebase.

-    // #[serde(rename = "nodeId")] // Handle JSON field `nodeId`
-    // pub node_id: String,

21-31: Payment Amount Type: Switch to Unsigned

After verifying the usage of the PayResponse struct across the codebase, there's no indication that negative values are ever expected for payment amounts. Since fields like amount_msat and amount_sent_msat represent inherently non-negative values, it would be more precise and safer to use u64 instead of i64.

-    pub amount_msat: i64,
-    pub amount_sent_msat: i64,
+    pub amount_msat: u64,
+    pub amount_sent_msat: u64,

34-60: Comprehensive Invoice and Outpoint structures

The PaidOutpoint and Invoice structs provide detailed definitions for handling payment data, with appropriate optional fields for handling various payment states.


67-85: Well-structured Bolt11 and Bolt12 response types

The response types for both BOLT11 and BOLT12 are well-defined, with appropriate fields for each protocol.


87-90: ListOffersResponse using PayCode from common types

The ListOffersResponse properly reuses the PayCode type defined in the common types, promoting code reuse.

bindings/lni_uniffi/src/lni.udl (5)

15-16: Renaming make_invoice to create_invoice is clear and consistent.


31-34: Keep security in mind for rune.

If rune is a sensitive token, confirm that no logs or error messages expose it. Would you like a script to scan for accidental logs or prints of rune across the repository?


36-63: New ClnNode interface looks well-structured.


137-138: New optional fields payer_note and external_id in Transaction.

Ensure these fields are returned and tested in the relevant endpoints or methods to maintain end-to-end consistency.


262-265: Replacing until, offset, etc., with payment_hash streamlines ListTransactionsParams.

crates/lni/cln/api.rs (10)

11-33: Use GET method and replace unwrap/println! with proper error handling and logging.
This function calls /v1/getinfo but uses a POST request instead of GET, and repeatedly calls .unwrap() and println!, which can cause panics and noisy console output in production environments.


35-129: Avoid blocking calls in async function and remove unwrap/println!.
This async function uses reqwest::blocking::Response, which defeats the purpose of async. Also, repeated .unwrap() calls can panic on errors, and printing to stdout via println! should be replaced with structured logging for production code.


131-146: Use async HTTP methods and structured error handling.
Similar to other functions, decode is declared async but relies on blocking requests and .unwrap(). Consider switching to reqwest::Client with async methods and replacing unwrap() with the ? operator or a custom error type.


168-195: Switch to async HTTP client and handle errors gracefully.
This function is declared async but uses reqwest::blocking::Response and multiple .unwrap() calls. For a more robust design, consider using an async client, removing blocking calls, and replacing .unwrap() with structured error handling.


197-246: Remove blocking calls and unwrap() from create_offer.
As an async function, create_offer should either use reqwest::Client with async methods or remove the async designation. Multiple .unwrap() calls may cause runtime panics; switch to the ? operator for robust error handling.


248-282: Use non-blocking calls in fetch_invoice_from_offer and avoid .unwrap().
Using blocking calls in an async context can lead to performance issues, and .unwrap() can cause panics. Consider adopting an async client and proper error propagation for resilience.


284-335: Eliminate blocking calls and unwrap() in pay_offer.
This exact pattern has been flagged previously: an async function should rely on non-blocking HTTP calls, and .unwrap() calls should be replaced with robust error handling to avoid panics.


337-403: Replace .unwrap() with safe error handling in lookup_invoice.
Here, multiple .unwrap() calls on sending requests and reading responses can crash the application if errors occur. Use ? or custom error handling to improve stability.


405-415: LGTM!
This function delegates to lookup_invoice and provides a clean error-forwarding approach with no direct unwrap usage. No issues found here.


417-425: Remove unsafe TLS acceptance and replace unwrap() with structured error handling in clnrest_client.
Allowing invalid certificates by default is risky for production code. Also, any failure while building headers or the client will panic on .unwrap(). Make these behaviors configurable and use safe error handling.

@ntheile ntheile merged commit 6fa252d into master Mar 19, 2025
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Apr 7, 2025
@coderabbitai coderabbitai bot mentioned this pull request Apr 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant