@@ -303,16 +303,47 @@ def create_uma_invoice(
303303 amount_msats : int ,
304304 metadata : str ,
305305 expiry_secs : Optional [int ] = None ,
306+ signing_private_key : Optional [bytes ] = None ,
307+ receiver_identifier : Optional [str ] = None ,
306308 ) -> Invoice :
309+ """Creates a new invoice for the UMA protocol. The metadata is hashed and included in the invoice. This API
310+ generates a Lightning Invoice (follows the Bolt 11 specification) to request a payment from another Lightning Node.
311+ This should only be used for generating invoices for UMA, with `create_invoice` preferred in the general case.
312+
313+ Args:
314+ node_id: The node ID for which to create an invoice.
315+ amount_msats: The amount of the invoice in msats. You can create a zero-amount invoice to accept any payment amount.
316+ metadata: The LNURL metadata payload field in the initial payreq response. This wil be hashed and present in the
317+ h-tag (SHA256 purpose of payment) of the resulting Bolt 11 invoice. See
318+ [this spec](https://github.com/lnurl/luds/blob/luds/06.md#pay-to-static-qrnfclink) for details.
319+ expiry_secs: The number of seconds until the invoice expires. Defaults to 600.
320+ signing_private_key: The receiver's signing private key. Used to hash the receiver identifier.
321+ receiver_identifier: Optional identifier of the receiver. If provided, this will be hashed using a monthly-rotated
322+ seed and used for anonymized analysis.
323+ """
324+ receiver_hash = None
325+ if receiver_identifier is not None :
326+ if signing_private_key is None :
327+ raise LightsparkException (
328+ "CreateUmaInvoiceError" ,
329+ "Receiver identifier provided without signing private key" ,
330+ )
331+ receiver_hash = self .hash_uma_identifier (
332+ receiver_identifier , signing_private_key
333+ )
334+
335+ variables = {
336+ "amount_msats" : amount_msats ,
337+ "node_id" : node_id ,
338+ "metadata_hash" : sha256 (metadata .encode ("utf-8" )).hexdigest (),
339+ "expiry_secs" : expiry_secs if expiry_secs is not None else 600 ,
340+ }
341+ if receiver_hash is not None :
342+ variables ["receiver_hash" ] = receiver_hash
307343 logger .info ("Creating an uma invoice for node %s." , node_id )
308344 json = self ._requester .execute_graphql (
309345 CREATE_UMA_INVOICE_MUTATION ,
310- {
311- "amount_msats" : amount_msats ,
312- "node_id" : node_id ,
313- "metadata_hash" : sha256 (metadata .encode ("utf-8" )).hexdigest (),
314- "expiry_secs" : expiry_secs if expiry_secs is not None else 600 ,
315- },
346+ variables ,
316347 )
317348
318349 return Invoice_from_json (self ._requester , json ["create_uma_invoice" ]["invoice" ])
@@ -530,7 +561,36 @@ def pay_uma_invoice(
530561 maximum_fees_msats : int ,
531562 amount_msats : Optional [int ] = None ,
532563 idempotency_key : Optional [str ] = None ,
564+ signing_private_key : Optional [bytes ] = None ,
565+ sender_identifier : Optional [str ] = None ,
533566 ) -> OutgoingPayment :
567+ """Sends an UMA payment to a node on the Lightning Network, based on the invoice (as defined by the BOLT11
568+ specification) that you provide. This should only be used for paying UMA invoices, with `pay_invoice` preferred
569+ in the general case.
570+
571+ Args:
572+ node_id: The ID of the node that will pay the invoice.
573+ encoded_invoice: The encoded invoice to pay.
574+ timeout_secs: A timeout for the payment in seconds.
575+ maximum_fees_msats: Maximum fees (in msats) to pay for the payment.
576+ amount_msats: The amount to pay in msats for a zero-amount invoice. Defaults to the full amount of the
577+ invoice. Note, this parameter can only be passed for a zero-amount invoice. Otherwise, the call will fail.
578+ idempotency_key: An optional key to ensure idempotency of the payment.
579+ signing_private_key: The sender's signing private key. Used to hash the sender identifier.
580+ sender_identifier: Optional identifier of the sender. If provided, this will be hashed using a monthly-rotated
581+ seed and used for anonymized analysis.
582+ """
583+ sender_hash = None
584+ if sender_identifier is not None :
585+ if signing_private_key is None :
586+ raise LightsparkException (
587+ "PayUmaInvoiceError" ,
588+ "Sender identifier provided without signing private key" ,
589+ )
590+ sender_hash = self .hash_uma_identifier (
591+ sender_identifier , signing_private_key
592+ )
593+
534594 variables = {
535595 "node_id" : node_id ,
536596 "encoded_invoice" : encoded_invoice ,
@@ -541,6 +601,8 @@ def pay_uma_invoice(
541601 variables ["amount_msats" ] = amount_msats
542602 if idempotency_key is not None :
543603 variables ["idempotency_key" ] = idempotency_key
604+ if sender_hash is not None :
605+ variables ["sender_hash" ] = sender_hash
544606 json = self ._requester .execute_graphql (
545607 PAY_UMA_INVOICE_MUTATION ,
546608 variables ,
@@ -933,6 +995,11 @@ def _hash_phone_number(self, phone_number_e164_format: str) -> str:
933995 )
934996 return sha256 (phone_number_e164_format .encode ()).hexdigest ()
935997
998+ def hash_uma_identifier (self , identifier : str , signing_private_key : bytes ) -> str :
999+ now = datetime .now (timezone .utc )
1000+ input_data = identifier + f"{ now .month } -{ now .year } " + signing_private_key .hex ()
1001+ return sha256 (input_data .encode ()).hexdigest ()
1002+
9361003 def fail_htlcs (self , invoice_id : str , cancel_invoice : bool = True ) -> str :
9371004 """
9381005 Fails all pending HTLCs associated with an invoice.
0 commit comments