Skip to content

Swap leaves to ensure quoted leave amount does not change above limit#741

Closed
danielgranhao wants to merge 6 commits intomainfrom
daniel-fix-onchain-quote-invalidated-by-leaf-set-changes
Closed

Swap leaves to ensure quoted leave amount does not change above limit#741
danielgranhao wants to merge 6 commits intomainfrom
daniel-fix-onchain-quote-invalidated-by-leaf-set-changes

Conversation

@danielgranhao
Copy link
Collaborator

Replaces #730. Closes #697 (resolving the underlying issue using a different strategy from what was suggested in the issue)

When an on-chain withdrawal fee quote is fetched, the SSP bases fees on the current leaf count. If leaves change between quoting and sending (e.g., due to incoming payments splitting leaves), the leaf count may exceed the SSP's tolerance, causing the withdrawal to fail.

This PR:

  • Records the quoted leaf count when fetching a fee quote
  • Computes the SSP's max allowed leaf count using ceil(q * (1.2 + 1.0 / q^0.6))
  • Passes a max_amount_leaf_count constraint through leaf selection, forcing a consolidation swap if needed
  • Rejects the withdrawal if the swap still can't bring the count within tolerance
  • Adds an integration test covering this scenario

@danielgranhao danielgranhao marked this pull request as ready for review March 16, 2026 11:12
@danielgranhao danielgranhao requested review from JssDWt, dangeross, hydra-yse and roeierez and removed request for dangeross and roeierez March 16, 2026 11:12
Copy link
Member

@roeierez roeierez left a comment

Choose a reason for hiding this comment

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

Nice and simple!

@danielgranhao
Copy link
Collaborator Author

danielgranhao commented Mar 16, 2026

Added a commit for improving the behavior when FeesIncluded is used. There was a relatively high risk of issues because, in this case, we want to send an amount less than the initially quoted amount. For certain values and depending on the fee, this makes it impossible to respect the max. Example: try to send 16384 sats (power of 2) -> we use a single leaf for the quote -> we try to send (16384 - selected fee), which is practically guaranteed to use more than 2 leaves (max allowed by SSP).

To fix this, I've changed the amount we use to get the quote. When fees are included, we use a worst case value: prev_power_of_2(amount) - 1 (e.g. for 16384, we quote for 16383). This value has the maximum number of set bits (= popcount) that any value below amount can have, so any amount - fee is guaranteed to need at most that many leaves. This way, the SSP's leaf count tolerance is always sufficient regardless of the fee. This works because SSP quotes are not tied to the amount that is sent.

@danielgranhao danielgranhao requested a review from roeierez March 16, 2026 18:03
@danielgranhao danielgranhao requested a review from roeierez March 17, 2026 10:05
Copy link
Member

@roeierez roeierez left a comment

Choose a reason for hiding this comment

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

LGTM

@danielgranhao
Copy link
Collaborator Author

We've discussed with Lightspark and it seems they may soon remove the leaf count change quote validation, making this unnecessary. Closing.

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.

Allow reserve leaves for co-operative exit

2 participants