invoices: Use the same base method to export invoices and requests.
This fixes an inconsistency where the 'expiration' field was relative for invoices, and absolute timestamp for requests. This in turn fixes QML the timer refreshing the request list. In order to prevent any API using that field from being silently broken, the 'expiration' field is renamed as 'expiry'.
This commit is contained in:
@@ -975,7 +975,7 @@ class Commands:
|
||||
return wallet.get_unused_address()
|
||||
|
||||
@command('w')
|
||||
async def add_request(self, amount, memo='', expiration=3600, force=False, wallet: Abstract_Wallet = None):
|
||||
async def add_request(self, amount, memo='', expiry=3600, force=False, wallet: Abstract_Wallet = None):
|
||||
"""Create a payment request, using the first unused address of the wallet.
|
||||
The address will be considered as used after this operation.
|
||||
If no payment is received, the address will be considered as unused if the payment request is deleted from the wallet."""
|
||||
@@ -986,8 +986,8 @@ class Commands:
|
||||
else:
|
||||
return False
|
||||
amount = satoshis(amount)
|
||||
expiration = int(expiration) if expiration else None
|
||||
key = wallet.create_request(amount, memo, expiration, addr)
|
||||
expiry = int(expiry) if expiry else None
|
||||
key = wallet.create_request(amount, memo, expiry, addr)
|
||||
req = wallet.get_request(key)
|
||||
return wallet.export_request(req)
|
||||
|
||||
@@ -1429,7 +1429,7 @@ command_options = {
|
||||
'addtransaction': (None,'Whether transaction is to be used for broadcasting afterwards. Adds transaction to the wallet'),
|
||||
'domain': ("-D", "List of addresses"),
|
||||
'memo': ("-m", "Description of the request"),
|
||||
'expiration': (None, "Time in seconds"),
|
||||
'expiry': (None, "Time in seconds"),
|
||||
'timeout': (None, "Timeout in seconds"),
|
||||
'force': (None, "Create new address beyond gap limit, if no more addresses are available."),
|
||||
'pending': (None, "Show only pending requests."),
|
||||
|
||||
@@ -15,7 +15,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
|
||||
# define listmodel rolemap
|
||||
_ROLE_NAMES=('key', 'is_lightning', 'timestamp', 'date', 'message', 'amount',
|
||||
'status', 'status_str', 'address', 'expiration', 'type', 'onchain_fallback',
|
||||
'status', 'status_str', 'address', 'expiry', 'type', 'onchain_fallback',
|
||||
'lightning_invoice')
|
||||
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
|
||||
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
|
||||
@@ -132,8 +132,8 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
|
||||
nearest_interval = LN_EXPIRY_NEVER
|
||||
for invoice in self.invoices:
|
||||
if invoice['status'] != PR_EXPIRED:
|
||||
if invoice['expiration'] > 0 and invoice['expiration'] != LN_EXPIRY_NEVER:
|
||||
interval = status_update_timer_interval(invoice['timestamp'] + invoice['expiration'])
|
||||
if invoice['expiry'] > 0 and invoice['expiry'] != LN_EXPIRY_NEVER:
|
||||
interval = status_update_timer_interval(invoice['timestamp'] + invoice['expiry'])
|
||||
if interval > 0:
|
||||
nearest_interval = nearest_interval if nearest_interval < interval else interval
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import attr
|
||||
|
||||
from .json_db import StoredObject
|
||||
from .i18n import _
|
||||
from .util import age, InvoiceError
|
||||
from .util import age, InvoiceError, format_satoshis
|
||||
from .lnutil import hex_to_bytes
|
||||
from .lnaddr import lndecode, LnAddr
|
||||
from . import constants
|
||||
@@ -222,6 +222,23 @@ class BaseInvoice(StoredObject):
|
||||
else: # on-chain
|
||||
return get_id_from_onchain_outputs(outputs=self.get_outputs(), timestamp=self.time)
|
||||
|
||||
def as_dict(self, status):
|
||||
d = {
|
||||
'is_lightning': self.is_lightning(),
|
||||
'amount_BTC': format_satoshis(self.get_amount_sat()),
|
||||
'message': self.message,
|
||||
'timestamp': self.get_time(),
|
||||
'expiry': self.exp,
|
||||
'status': status,
|
||||
'status_str': self.get_status_str(status),
|
||||
'id': self.get_id(),
|
||||
'amount_sat': int(self.get_amount_sat()),
|
||||
}
|
||||
if self.is_lightning():
|
||||
d['amount_msat'] = self.get_amount_msat()
|
||||
return d
|
||||
|
||||
|
||||
@attr.s
|
||||
class Invoice(BaseInvoice):
|
||||
lightning_invoice = attr.ib(type=str, kw_only=True) # type: Optional[str]
|
||||
|
||||
@@ -2459,34 +2459,20 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
def export_request(self, x: Request) -> Dict[str, Any]:
|
||||
key = x.get_id()
|
||||
status = self.get_invoice_status(x)
|
||||
status_str = x.get_status_str(status)
|
||||
is_lightning = x.is_lightning()
|
||||
address = x.get_address()
|
||||
d = {
|
||||
'is_lightning': is_lightning,
|
||||
'amount_BTC': format_satoshis(x.get_amount_sat()),
|
||||
'message': x.message,
|
||||
'timestamp': x.get_time(),
|
||||
'expiration': x.get_expiration_date(),
|
||||
'status': status,
|
||||
'status_str': status_str,
|
||||
'request_id': key,
|
||||
"tx_hashes": []
|
||||
}
|
||||
if is_lightning:
|
||||
d = x.as_dict(status)
|
||||
d['request_id'] = d.pop('id')
|
||||
if x.is_lightning():
|
||||
d['rhash'] = x.rhash
|
||||
d['lightning_invoice'] = self.get_bolt11_invoice(x)
|
||||
d['amount_msat'] = x.get_amount_msat()
|
||||
if self.lnworker and status == PR_UNPAID:
|
||||
d['can_receive'] = self.lnworker.can_receive_invoice(x)
|
||||
if address:
|
||||
d['amount_sat'] = int(x.get_amount_sat())
|
||||
if address := x.get_address():
|
||||
d['address'] = address
|
||||
d['URI'] = self.get_request_URI(x)
|
||||
# if request was paid onchain, add relevant fields
|
||||
# note: addr is reused when getting paid on LN! so we check for that.
|
||||
_, conf, tx_hashes = self._is_onchain_invoice_paid(x)
|
||||
if not is_lightning or not self.lnworker or self.lnworker.get_invoice_status(x) != PR_PAID:
|
||||
if not x.is_lightning() or not self.lnworker or self.lnworker.get_invoice_status(x) != PR_PAID:
|
||||
if conf is not None:
|
||||
d['confirmations'] = conf
|
||||
d['tx_hashes'] = tx_hashes
|
||||
@@ -2496,27 +2482,15 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
def export_invoice(self, x: Invoice) -> Dict[str, Any]:
|
||||
key = x.get_id()
|
||||
status = self.get_invoice_status(x)
|
||||
status_str = x.get_status_str(status)
|
||||
is_lightning = x.is_lightning()
|
||||
d = {
|
||||
'is_lightning': is_lightning,
|
||||
'amount_BTC': format_satoshis(x.get_amount_sat()),
|
||||
'message': x.message,
|
||||
'timestamp': x.time,
|
||||
'expiration': x.exp,
|
||||
'status': status,
|
||||
'status_str': status_str,
|
||||
'invoice_id': key,
|
||||
}
|
||||
if is_lightning:
|
||||
d = x.as_dict(status)
|
||||
d['invoice_id'] = d.pop('id')
|
||||
if x.is_lightning():
|
||||
d['lightning_invoice'] = x.lightning_invoice
|
||||
d['amount_msat'] = x.get_amount_msat()
|
||||
if self.lnworker and status == PR_UNPAID:
|
||||
d['can_pay'] = self.lnworker.can_pay_invoice(x)
|
||||
else:
|
||||
amount_sat = x.get_amount_sat()
|
||||
assert isinstance(amount_sat, (int, str, type(None)))
|
||||
d['amount_sat'] = amount_sat
|
||||
d['outputs'] = [y.to_legacy_tuple() for y in x.get_outputs()]
|
||||
if x.bip70:
|
||||
d['bip70'] = x.bip70
|
||||
|
||||
Reference in New Issue
Block a user