Skip to content

Conversation

@arkanoider
Copy link
Collaborator

@arkanoider arkanoider commented Aug 21, 2025

@grunch ,

since it comes to zero effort, i will drop this PR and let you decide if it is worth to merge it, as I said in tg chat this allow with new config parameter called nip40_expiration_days to define the days before nip40 on relay is triggered so now total life time of the order event is:

lifetime = now() + expires_at + nip40_expiration_days

now nip40_expiration_days is basically hardcoded to 24h.

Summary by CodeRabbit

  • New Features

    • Orders now honor a configurable Nip-40 expiration grace period instead of a fixed 24-hour extension (default: 15 days); configurable via settings.
  • Tests

    • Tests expanded to cover the new expiration setting.
    • Updated zero-amount invoice sample used in validation tests.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Walkthrough

Adds a new Mostro configuration setting nip40_expiration_days and uses it in NIP-33 tag generation to compute expiration dynamically. Updates config types and tests, and replaces a test invoice string; no public function signatures changed.

Changes

Cohort / File(s) Summary
Config: template & types
settings.tpl.toml, src/config/types.rs
Adds mostro.nip40_expiration_days = 15 to the template and pub nip40_expiration_days: u32 to MostroSettings.
Config: tests
src/config/mod.rs
Updates test TOML and asserts the new nip40_expiration_days field is parsed as 15.
NIP-33 dynamic expiration
src/nip33.rs
order_to_tags now reads nip40_expiration_days via Settings::get_mostro() and computes expiration as order.expires_at + Duration::days(nip40_expiration_days) instead of a fixed 24h offset.
Lightning test data update
src/lightning/invoice.rs
Replaces the BOLT11 test invoice string in test_zero_amount_invoice; test logic unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant P as Publisher
  participant N as order_to_tags
  participant S as Settings
  participant C as Config Store
  participant T as Tags

  P->>N: order_to_tags(order)
  N->>S: Settings::get_mostro()
  S->>C: read MostroSettings
  C-->>S: { nip40_expiration_days, ... }
  S-->>N: MostroSettings

  Note over N: Compute expiration = order.expires_at + days(nip40_expiration_days)

  N->>T: add ["expiration", computed_seconds]
  N-->>P: Tags
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10–15 minutes

Possibly related PRs

Suggested reviewers

  • grunch
  • Catrya

Poem

A nibble of days in a carrot of conf,
I hop through tags where seconds drift on.
Orders stretch sunsets by fifteen small hops,
Tests updated, invoices kept strong.
Thump goes my paw — configuration done! 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2b743c5 and f456443.

📒 Files selected for processing (1)
  • settings.tpl.toml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • settings.tpl.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch nip40-expiration-parameter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@arkanoider arkanoider requested review from Catrya and grunch August 21, 2025 09:46
Copy link
Contributor

@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 (4)
src/lightning/invoice.rs (1)

286-291: Zero-amount test uses a hard-coded BOLT11 that can expire over time

The new invoice string is embedded with a fixed timestamp; once expired, this test will start failing intermittently. Also, the other tests use regtest invoices (lnbcrt...), while this one is mainnet (lnbc...), which is inconsistent.

Consider making the test time-agnostic or at least guarding against accidental expiry.

Apply this guard so failures clearly indicate an expired vector and not a logic regression:

 async fn test_zero_amount_invoice() {
     init_settings_test();
-    let payment_request = "lnbc1p52v0v9pp5scdu5kh9gkgp63r7k72pugffkut4uqdv98d7vruvanklt700rmrsdq5g9kxy7fqd9h8vmmfvdjscqzzsxqyz5vqsp5tw8kcvr22mlmdffrtfta6xxhhl5cdtnpg02qygvr2yhm3vva9zas9qxpqysgqecamkem2pcz8savcv8j7p3uj6lxlx5dnecc26ax5uk005aqfdszsdxfuchsph6tej8j08eps3np5ukvv6t6nfldkge76qyn3qs0p23gqy2jj0z".to_string();
+    let payment_request = "lnbc1p52v0v9pp5scdu5kh9gkgp63r7k72pugffkut4uqdv98d7vruvanklt700rmrsdq5g9kxy7fqd9h8vmmfvdjscqzzsxqyz5vqsp5tw8kcvr22mlmdffrtfta6xxhhl5cdtnpg02qygvr2yhm3vva9zas9qxpqysgqecamkem2pcz8savcv8j7p3uj6lxlx5dnecc26ax5uk005aqfdszsdxfuchsph6tej8j08eps3np5ukvv6t6nfldkge76qyn3qs0p23gqy2jj0z".to_string();
+    // Defensive check so failures are self-explanatory if the static vector ever expires.
+    let inv = decode_invoice(&payment_request).expect("invoice must decode");
+    assert!(!inv.is_expired(), "zero-amount test vector expired; update payment_request");
     let zero_amount_err = is_valid_invoice(payment_request, Some(100), None);
     assert_eq!(Ok(()), zero_amount_err.await);
 }

If feasible, prefer generating a fresh zero-amount invoice at runtime (or injecting “now” into validation) to fully eliminate time-coupling. I can draft that if desired.

src/config/mod.rs (1)

78-79: Tests updated for new key; add a regression test for missing-key default

The assertions for nip40_expiration_days = 15 look good. To prevent future regressions and to cover migration scenarios where existing configs lack this key, add a test that omits it and validates the deserialized default (ideally 1 day per the compatibility suggestion).

You can add the following test:

#[test]
fn test_mostro_settings_default_nip40_expiration_days() {
    // Same MOSTRO_SETTINGS TOML but without `nip40_expiration_days`
    const MOSTRO_SETTINGS_NO_NIP40: &str = r#"[mostro]
        fee = 0
        max_routing_fee = 0.001
        max_order_amount = 1000000
        min_payment_amount = 100
        expiration_hours = 24
        max_expiration_days = 15
        expiration_seconds = 900
        user_rates_sent_interval_seconds = 3600
        publish_relays_interval = 60
        pow = 0
        publish_mostro_info_interval = 300
        bitcoin_price_api_url = "https://api.yadio.io""#;

    #[derive(Debug, Deserialize)]
    struct Stub { mostro: MostroSettings }

    let settings: Stub = toml::from_str(MOSTRO_SETTINGS_NO_NIP40).expect("Failed to deserialize");
    // Expect 1 if we preserve prior 24h behavior via serde default.
    assert_eq!(settings.mostro.nip40_expiration_days, 1);
}

Also applies to: 165-166

settings.tpl.toml (1)

38-39: Clarify semantics and consider a backward-compatible default

Good addition. To minimize surprises for operators, set the template’s default to the prior implicit value (e.g., 1) and document precisely how it’s applied.

Apply:

-# Nip40 expiration days
-nip40_expiration_days = 15
+# NIP-40 expiration grace in days (added to `order.expires_at` when generating the expiration tag).
+# This controls how long the event remains on relays after the order itself expires.
+# Set to 0 to disable any extra grace period.
+nip40_expiration_days = 1

If you want 15 as the new recommended value, keep 15 here but ensure serde default is 1 to preserve legacy behavior for configs missing this key.

src/nip33.rs (1)

246-250: Dynamic NIP-40 expiration computation — confirm desired default and consider saturating add

The computation is correct. Be mindful that with the new field defaulting to 0, events will have no extra grace unless operators set the key. If you aim to preserve the prior 24h behavior by default, couple this with a serde default of 1 day in MostroSettings.

Optionally, make the addition explicit and saturating to guard against extreme configuration values (defense-in-depth; harmless overhead):

-                vec![(order.expires_at
-                    + Duration::days(mostro_settings.nip40_expiration_days as i64).num_seconds())
-                .to_string()],
+                vec![
+                    (order.expires_at.saturating_add(
+                        Duration::days(mostro_settings.nip40_expiration_days as i64).num_seconds(),
+                    ))
+                    .to_string()
+                ],

Also consider exposing nip40_expiration_days in info_to_tags so clients can introspect runtime policy.

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6cca4bb and 2b743c5.

📒 Files selected for processing (5)
  • settings.tpl.toml (1 hunks)
  • src/config/mod.rs (2 hunks)
  • src/config/types.rs (1 hunks)
  • src/lightning/invoice.rs (1 hunks)
  • src/nip33.rs (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-17T13:51:17.338Z
Learnt from: arkanoider
PR: MostroP2P/mostro#499
File: src/lightning/invoice.rs:108-114
Timestamp: 2025-07-17T13:51:17.338Z
Learning: In Lightning invoice validation for Mostro buy orders (src/lightning/invoice.rs), zero-amount invoices (amount_sat == 0) should always pass validation even when an expected amount is provided. This is because users can submit invoices at order creation time before knowing the exact satoshi amount they'll receive. The condition `if amount_sat != res && amount_sat != 0` correctly implements this by allowing zero-amount invoices to pass while enforcing exact amount matching for non-zero invoices.

Applied to files:

  • src/lightning/invoice.rs
🧬 Code graph analysis (2)
src/nip33.rs (1)
src/config/settings.rs (1)
  • get_mostro (58-63)
src/config/types.rs (1)
src/config/settings.rs (1)
  • Settings (23-34)
🔇 Additional comments (1)
src/nip33.rs (1)

199-201: Fetching Mostro settings here is appropriate

Using Settings::get_mostro() locally in order_to_tags keeps concerns contained. No issues.

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.

2 participants