Skip to content

millisat precision#10586

Draft
accumulator wants to merge 30 commits intospesmilo:masterfrom
accumulator:millisat_precision
Draft

millisat precision#10586
accumulator wants to merge 30 commits intospesmilo:masterfrom
accumulator:millisat_precision

Conversation

@accumulator
Copy link
Copy Markdown
Member

@accumulator accumulator commented Apr 17, 2026

support millisat precision throughout the codebase.

  • kwarged backend wallet funcs so it is clear whether sats or millisats as ints are passed
  • lnurl now native millisats
  • Decimal is used on the GUI side where it's easier to assume sats are the base unit
    • avoids having to check sat and msat fields/parameters
    • can check easily if amount has millisat precision where not allowed
    • extra millisat precision is carried transparently for eventual passing to backend
  • QML QEAmount is now synced between sats and millisats, simplifying assumptions and reducing if-else checks

should fix #6253, #10412

…imal point and

extra_precision up to AmountEdit
…to encapsulate fx base unit and

precision, extra_precision now a callable and retrieved dynamically.
BTCAmountEdit extended with millisat_precision option kwarg to allow 3 digits extra precision.
add amount_msat parameter and make mutually exclusive with amount_sat
qt: send_tab LN checks millisat precision
Comment on lines 22 to 26
property int walletCanReceive: 0
property int providerMinWithdrawable: parseInt(requestDetails.lnurlData['min_withdrawable_sat'])
property int providerMaxWithdrawable: parseInt(requestDetails.lnurlData['max_withdrawable_sat'])
property int providerMinWithdrawable: parseInt(requestDetails.lnurlData['min_withdrawable_msat'])
property int providerMaxWithdrawable: parseInt(requestDetails.lnurlData['max_withdrawable_msat'])
property int effectiveMinWithdrawable: Math.max(providerMinWithdrawable, 1)
property int effectiveMaxWithdrawable: Math.min(providerMaxWithdrawable, walletCanReceive)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The Claude CI task AFAICT correctly flagged (a preexisting) overflow issue here: property int is a signed 32-bit int, which is too small for this usecase.
The max value is around 21 BTC with sat units, and around 21 mBTC with msat units.

Copy link
Copy Markdown
Member Author

@accumulator accumulator Apr 20, 2026

Choose a reason for hiding this comment

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

Yes this is a long-standing issue, hence the use of QEAmount. A short summary of the issues:

  • integers in javascript context have a max range of +/- 2^54-1, which allows 21M BTC expressed in sats, but not in msats.
  • QML int properties have a max range of +/- 2^31-1, which only allows 21 BTC expressed in sats, 21 mBTC expressed in msats (like you already indicated above)
  • int parameters declared in the pyqtProperty and pyqtSlot decorators have a max range of 2^31-1, although this is somewhat alleviated in the QML->Python direction by using q(u)int64. Returning a q(u)int64 does not work around the int limitation if I remember correctly (I think this was observed using Qt5, and when initially porting to Qt6)

In most of the QML code, QEAmount is already used for storing and passing around BTC values. The only exception is where amounts are compared (e.g. invoice amount < available balance etc) , so the <, >, <=, >= and != operators, and where these operators are implied, like Math.min() and Math.max()

I'm adding patches to add these operators as pyqtSlots so the operators are executed in python context. Possible caveat is that pyqtSlot calls might not be re-evaluated when used in a QML property binding.

@accumulator accumulator marked this pull request as draft April 20, 2026 07:23
@accumulator accumulator force-pushed the millisat_precision branch 3 times, most recently from 4b880f3 to 89e6833 Compare April 20, 2026 09:14
QEConfig.satsToUnits to QEConfig.amountToBaseunitStr with the latter now
also taking a QEAmount instance
@accumulator accumulator force-pushed the millisat_precision branch 5 times, most recently from 0e96f76 to 482281d Compare April 20, 2026 12:36
Using javascript or QML `int` type is a long-standing issue, as there is not enough range to express millisats or even sats.
A short summary of the issues:
- integers in javascript context have a max range of +/- 2^54-1, which allows 21M BTC expressed in sats, but not in msats.
- QML `int` properties have a max range of +/- 2^31-1, which only allows 21 BTC expressed in sats, 21 mBTC expressed in msats
- `int` parameters declared in the `pyqtProperty` and `pyqtSlot` decorators have a max range of 2^31-1,
although this is somewhat alleviated in the QML->Python direction by using `q(u)int64`. Returning a `q(u)int64` does not
work around the `int` limitation

In most of the QML code, `QEAmount` is already used for storing and passing around BTC values.
The only exception is where amounts are compared (e.g. invoice amount < available balance etc),
so the `<`, `>`, `<=`, `>=` and `!=` operators, and where these operators are implied, like `Math.min()` and `Math.max()`

This commit delegates these operators to python scope.
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.

user interface only has satoshi precision (msat truncated to sat, rounding)

2 participants