Skip to content

rfq: add limit constraints and quote-level enforcement to rfq negotiation#2048

Open
jtobin wants to merge 10 commits intolightninglabs:mainfrom
jtobin:limit-constraints
Open

rfq: add limit constraints and quote-level enforcement to rfq negotiation#2048
jtobin wants to merge 10 commits intolightninglabs:mainfrom
jtobin:limit-constraints

Conversation

@jtobin
Copy link
Copy Markdown
Member

@jtobin jtobin commented Apr 3, 2026

Partially resolves #2004 (roughly, workstreams A and B).

Adds limit order constraint fields to the RFQ wire protocol and RPC surface. Opus-generated TLDR for these changes:

  • Users can specify explicit limit-price bounds for buy and sell RFQ orders
  • Users can specify minimum fill constraints
  • Quotes violating constraints are rejected with machine-readable reasons (enforcement in this changeset is only at the quote acceptance level)
  • Accepted quotes cannot pass validation if they violate requester limits
  • Backward-compatible; new fields are optional TLVs, and validation is gated on presence.

For illustration of the kind of thing this enables, here's an example scenario from an e2e regtest demo of this (and related) functionality:

  Frank buys 1,000 USDX ($10.00) with a price ceiling at ~105% of market
  — he won't pay more than that per USDX. The pilot's price is below the
  ceiling, so the quote is accepted and payment executes through the asset
  channel.

  Price ceiling: 15.7 sats/USDX
  Pilot price:   14.9 sats/USDX
  ✓ Accepted
    RFQ ID: klOI8CDwIdlt...
    Rate:   $66,805.00/BTC
    Amount: 1000 USDX
    Limit:  rate_floor coeff=6346475 ($63,464.75/BTC)

  → AddInvoice (rfq_id: klOI8CDwIdlt...)
    1000 USDX from Frank, reusing negotiated quote
    Quote confirmed: klOI8CDwIdlt...
    Invoice: lnbcrt149689390p1p5ulzhwpp5dp476qtl95kzq...

  → Payment: Alice → Eve → Frank
    ✓ Payment succeeded

jtobin added 8 commits April 3, 2026 18:57
Add a new optional TLV field (Type 29, TlvFixedPoint) to
requestWireMsgData for carrying rate limit constraints on
quote requests. This field supports both buy requests
(minimum acceptable rate) and sell requests (maximum
acceptable rate).

Wire encode/decode follows the existing InAssetRateHint
pattern.
Add AssetMinAmt and AssetRateLimit to BuyRequest, and
PaymentMinAmt and AssetRateLimit to SellRequest. Update
constructors, FromWire extraction, Validate (min <= max,
rate positive), String output, and wire bridging functions.

Add corresponding fields to BuyOrder and SellOrder structs
and thread them through the negotiator's outgoing order
handlers. Existing callers pass fn.None for both new params.
Add min fill and rate limit fields to RFQ and portfolio pilot proto
definitions. Update rpcserver unmarshalling, portfolio pilot RPC
marshal/unmarshal functions, and add new reject codes and quote
response status values.
Add checkRateBound and checkMinFill enforcement to the internal
portfolio pilot's VerifyAcceptQuote. Rate bound checks that the
accepted rate satisfies the requester's limit (floor for buy,
ceiling for sell). Min fill checks that the minimum amount is
transportable at the accepted rate.

Also adds MinFillNotMetRejectCode, PriceBoundMissRejectCode,
and corresponding QuoteRespStatus values.
Add typed roundtrip tests for BuyRequest and SellRequest covering
min fill, rate limit, and backward-compatible no-optional-field
cases. Add validation tests for min > max and zero rate limit.

Add rapid-based property tests covering wire roundtrip, min/max
constraint validation, and rate bound enforcement semantics for both buy
and sell requests.

Extend TestVerifyAcceptQuote with rate bound enforcement cases
(buy below/at/above limit, sell above/at limit) and min fill
cases (zero msat, transportable). Add dedicated unit tests for
checkRateBound and checkMinFill helpers.

Update wire-level roundtrip test to cover AssetRateLimit TLV 29.
Add Validate() to NewBuyRequest and NewSellRequest constructors so
that invalid requests (e.g. min > max) are caught locally before
being sent over the wire.

Add testRfqLimitConstraints: a pure RFQ integration test with five
sub-tests exercising buy/sell orders with satisfied and violated
rate limits, plus client-side min > max rejection.

Add testCustomChannelsLimitConstraints: a custom channels smoke
test that negotiates a sell quote with asset_rate_limit and
payment_min_amt constraints over a real asset channel, then pays
an invoice using the pre-negotiated quote.
Harden rate limit validation to reject negative coefficients (not
just zero), add default cases to checkRateBound/checkMinFill type
switches, fix stale godoc on unmarshalOptionalFixedPoint, path-
anchor the gitignore entry, rewrite TestRateBoundEnforcementProperty
to exercise wire roundtrip code, and add TestNegativeRateLimitRejected.
@jtobin jtobin added this to the v0.8 milestone Apr 3, 2026
@jtobin jtobin self-assigned this Apr 3, 2026
@jtobin jtobin added the RFQ Work relating to TAP channel Request For Quote (RFQ). label Apr 3, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the Request-for-Quote (RFQ) negotiation protocol by introducing client-side limit-order constraints. These changes allow users to define price boundaries and minimum fill requirements for their orders, which are then enforced during the quote acceptance process. The implementation is designed to be backward-compatible and includes robust validation logic to ensure that quotes violating these constraints are rejected with specific, machine-readable error codes.

Highlights

  • Limit-Order Constraints: Added support for explicit limit-price bounds (asset_rate_limit) and minimum fill constraints (asset_min_amt / payment_min_amt) for RFQ buy and sell orders.
  • Machine-Readable Rejections: Introduced new error statuses (RATE_BOUND_MISS, MIN_FILL_NOT_MET) to provide clear feedback when quotes violate specified constraints.
  • Backward Compatibility: The new constraint fields are implemented as optional TLVs, ensuring that validation is only enforced when these fields are present.
  • Testing: Added comprehensive unit, property-based, and integration tests to verify the enforcement of limit-order constraints.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces limit-order constraints for RFQ buy and sell orders, including new fields for minimum fill amounts and rate limits. The changes involve updating the RPC definitions, the RFQ manager, and the negotiator to enforce these constraints, along with comprehensive unit, property-based, and integration tests. I have no feedback to provide as the code changes are well-structured and the tests are thorough.

jtobin added 2 commits April 3, 2026 20:41
Fix gofmt alignment in rfq_test.go and request_property_test.go.
Fix line-length violations in portfolio_pilot.go,
portfolio_pilot_test.go, and request_property_test.go.

Remove PaymentMinAmt from rate-limit-focused sell sub-tests:
at the test oracle rate (1000 units/BTC), 1000 msat converts
to zero asset units, tripping the checkMinFill guard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RFQ Work relating to TAP channel Request For Quote (RFQ).

Projects

Status: 🆕 New

Development

Successfully merging this pull request may close these issues.

[feature]: RFQ: First-Class Limit Orders In Quote Negotiation

1 participant