Skip to content

feat: add mints_strict field to payment requests#2007

Open
d4rp4t wants to merge 3 commits into
cashubtc:mainfrom
d4rp4t:feat/nut18-nut28-mint-strict-flag
Open

feat: add mints_strict field to payment requests#2007
d4rp4t wants to merge 3 commits into
cashubtc:mainfrom
d4rp4t:feat/nut18-nut28-mint-strict-flag

Conversation

@d4rp4t

@d4rp4t d4rp4t commented May 26, 2026

Copy link
Copy Markdown

Description

Adds mints_strict (ms) field to PaymentRequest as specified in NUT-18 and NUT-26 PR: cashubtc/nuts#381

When ms is absent or true (default), the recipient MUST reject payments from mints not in the mint list. When ms is false, the mint list is a suggestion for the payer.

NUT-26 (bech32m) encoding adds TLV tag 0x09 for this field.

Notes to the reviewers

The field is serialized with skip_serializing_if = "Option::is_none" so existing encoded payment requests remain valid — absence of the tag is equivalent to true (strict mode), consistent with the proposed spec default.


Suggested CHANGELOG Updates

CHANGED

ADDED

  • mints_strict field (ms) to PaymentRequest (NUT-18) with corresponding TLV tag 0x09 in NUT-26 bech32m encoding
  • mints_strict() builder method on PaymentRequestBuilder

Checklist

  • I followed the code style guidelines
  • [] I ran just quick-check before committing
  • If the Wallet API was modified (added/removed/changed), I have reflected those changes in the FFI bindings (crates/cdk-ffi)

@github-project-automation github-project-automation Bot moved this to Backlog in CDK May 26, 2026
@d4rp4t d4rp4t mentioned this pull request May 26, 2026
3 tasks
@d4rp4t d4rp4t force-pushed the feat/nut18-nut28-mint-strict-flag branch from 085b13c to da6ce50 Compare June 14, 2026 22:05
@d4rp4t

d4rp4t commented Jun 14, 2026

Copy link
Copy Markdown
Author

Added changes so it matches: cashubtc/nuts#381

@thesimplekid

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da6ce50884

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/// Mints strict flag
#[serde(rename = "ms")]
#[serde(skip_serializing_if = "Option::is_none")]
pub mints_strict: Option<bool>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Honor non-strict mint lists when selecting a mint

When ms is Some(false), the mint list is only a suggestion, but WalletRepository::pay_request still rejects a specified mint and skips auto-selected wallets whenever payment_request.mints is non-empty. A payer with funds only at another mint will fail a non-strict request instead of using that mint, so the selection filters should be gated on mints_strict.unwrap_or(true).

Useful? React with 👍 / 👎.

Comment on lines +43 to +46
/// Additional fee reserve for payments from non-preferred mints
#[serde(rename = "fr")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fee_reserve: Option<Amount>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the unassigned fee reserve request field

The referenced NUT-18/NUT-26 change only adds ms/tag 0x09; fr is not defined for payment requests. Because this field and its builder method are serialized into CBOR and NUT-26 tag 0x0a when set, callers can emit non-standard requests that may collide with future tag assignments, so this should be removed until the NUT assigns it.

Useful? React with 👍 / 👎.

Comment on lines +47 to +50
/// Supported payment methods the mint must support
#[serde(rename = "sm")]
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub supported_methods: Vec<String>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Remove the unassigned supported methods field

The preferred-mints spec change does not define an sm payment-request field or NUT-26 tag 0x0b. If a caller sets supported_methods, this implementation serializes a non-standard field in both encodings, which other implementations may ignore and which can conflict with a future NUT assignment.

Useful? React with 👍 / 👎.

unit: Some(CurrencyUnit::from_str(&params.unit)?),
single_use: Some(true),
mints,
mints_strict: None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce strict mint lists when receiving Nostr payments

For Nostr requests created here, None means strict mode by default, but NostrWaitInfo does not retain the accepted mints and both wait_for_nostr_payment paths receive/create a wallet for any payload.mint. In Nostr receive flows this accepts payments from mints the request says must be rejected, so carry the mint policy into the wait info or pass the original request to wait_for_nostr_payment and check it before receiving.

Useful? React with 👍 / 👎.

Comment on lines +306 to +307
if !value.is_empty() {
mints_strict = Some(value[0] != 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject malformed mints_strict TLV values

NUT-26 defines tag 0x09 as a single u8 0/1, but this accepts empty values as absent and any multi-byte or non-zero value as true. A malformed CREQB with tag 0x09 length 2 decodes successfully and re-encodes to different canonical bytes, so check value.len() == 1 and matches!(value[0], 0 | 1) before setting the field.

Useful? React with 👍 / 👎.

Comment thread fuzz/src/arbitrary_ext.rs
unit,
single_use,
mints,
mints_strict: None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Generate mints_strict in structured fuzzing

The structured payment-request fuzzer round-trips PaymentRequestArb through CBOR, Bech32, and JSON, but the new mints_strict field is always None. That means regressions in serializing or decoding Some(false)/Some(true) will not be exercised by this target, so make this field fuzz-controlled like the other optional booleans.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants