payment_identifier: refactor round_3 to need_merchant_notify/notify_merchant
This commit is contained in:
@@ -632,10 +632,9 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
|||||||
return False, repr(e)
|
return False, repr(e)
|
||||||
# success
|
# success
|
||||||
txid = tx.txid()
|
txid = tx.txid()
|
||||||
if self.payment_identifier.needs_round_3():
|
if self.payment_identifier.need_merchant_notify():
|
||||||
refund_address = self.wallet.get_receiving_address()
|
refund_address = self.wallet.get_receiving_address()
|
||||||
coro = self.payment_identifier.round_3(tx.serialize(), refund_address)
|
self.payment_identifier.notify_merchant(tx=tx, refund_address=refund_address)
|
||||||
asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
|
|
||||||
return True, txid
|
return True, txid
|
||||||
|
|
||||||
# Capture current TL window; override might be removed on return
|
# Capture current TL window; override might be removed on return
|
||||||
|
|||||||
@@ -182,9 +182,13 @@ class PaymentIdentifierState(IntEnum):
|
|||||||
# of the channels Electrum supports (on-chain, lightning)
|
# of the channels Electrum supports (on-chain, lightning)
|
||||||
NEED_RESOLVE = 3 # PI contains a recognized destination format, but needs an online resolve step
|
NEED_RESOLVE = 3 # PI contains a recognized destination format, but needs an online resolve step
|
||||||
LNURLP_FINALIZE = 4 # PI contains a resolved LNURLp, but needs amount and comment to resolve to a bolt11
|
LNURLP_FINALIZE = 4 # PI contains a resolved LNURLp, but needs amount and comment to resolve to a bolt11
|
||||||
BIP70_VIA = 5 # PI contains a valid payment request that should have the tx submitted through bip70 gw
|
MERCHANT_NOTIFY = 5 # PI contains a valid payment request and on-chain destination. It should notify
|
||||||
|
# the merchant payment processor of the tx after on-chain broadcast,
|
||||||
|
# and supply a refund address (bip70)
|
||||||
|
MERCHANT_ACK = 6 # PI notified merchant. nothing to be done.
|
||||||
ERROR = 50 # generic error
|
ERROR = 50 # generic error
|
||||||
NOT_FOUND = 51 # PI contains a recognized destination format, but resolve step was unsuccesful
|
NOT_FOUND = 51 # PI contains a recognized destination format, but resolve step was unsuccesful
|
||||||
|
MERCHANT_ERROR = 52 # PI failed notifying the merchant after broadcasting onchain TX
|
||||||
|
|
||||||
|
|
||||||
class PaymentIdentifier(Logger):
|
class PaymentIdentifier(Logger):
|
||||||
@@ -221,6 +225,8 @@ class PaymentIdentifier(Logger):
|
|||||||
#
|
#
|
||||||
self.bip70 = None
|
self.bip70 = None
|
||||||
self.bip70_data = None
|
self.bip70_data = None
|
||||||
|
self.merchant_ack_status = None
|
||||||
|
self.merchant_ack_message = None
|
||||||
#
|
#
|
||||||
self.lnurl = None
|
self.lnurl = None
|
||||||
self.lnurl_data = None
|
self.lnurl_data = None
|
||||||
@@ -238,6 +244,9 @@ class PaymentIdentifier(Logger):
|
|||||||
def need_finalize(self):
|
def need_finalize(self):
|
||||||
return self._state == PaymentIdentifierState.LNURLP_FINALIZE
|
return self._state == PaymentIdentifierState.LNURLP_FINALIZE
|
||||||
|
|
||||||
|
def need_merchant_notify(self):
|
||||||
|
return self._state == PaymentIdentifierState.MERCHANT_NOTIFY
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
return self._state not in [PaymentIdentifierState.INVALID, PaymentIdentifierState.EMPTY]
|
return self._state not in [PaymentIdentifierState.INVALID, PaymentIdentifierState.EMPTY]
|
||||||
|
|
||||||
@@ -250,9 +259,6 @@ class PaymentIdentifier(Logger):
|
|||||||
def get_error(self) -> str:
|
def get_error(self) -> str:
|
||||||
return self.error
|
return self.error
|
||||||
|
|
||||||
def needs_round_3(self):
|
|
||||||
return self.bip70
|
|
||||||
|
|
||||||
def parse(self, text):
|
def parse(self, text):
|
||||||
# parse text, set self._type and self.error
|
# parse text, set self._type and self.error
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
@@ -304,11 +310,11 @@ class PaymentIdentifier(Logger):
|
|||||||
|
|
||||||
def resolve(self, *, on_finished: 'Callable'):
|
def resolve(self, *, on_finished: 'Callable'):
|
||||||
assert self._state == PaymentIdentifierState.NEED_RESOLVE
|
assert self._state == PaymentIdentifierState.NEED_RESOLVE
|
||||||
coro = self.do_resolve(on_finished=on_finished)
|
coro = self._do_resolve(on_finished=on_finished)
|
||||||
asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
||||||
|
|
||||||
@log_exceptions
|
@log_exceptions
|
||||||
async def do_resolve(self, *, on_finished=None):
|
async def _do_resolve(self, *, on_finished=None):
|
||||||
try:
|
try:
|
||||||
if self.emaillike:
|
if self.emaillike:
|
||||||
data = await self.resolve_openalias()
|
data = await self.resolve_openalias()
|
||||||
@@ -338,7 +344,7 @@ class PaymentIdentifier(Logger):
|
|||||||
from . import paymentrequest
|
from . import paymentrequest
|
||||||
data = await paymentrequest.get_payment_request(self.bip70)
|
data = await paymentrequest.get_payment_request(self.bip70)
|
||||||
self.bip70_data = data
|
self.bip70_data = data
|
||||||
self.set_state(PaymentIdentifierState.BIP70_VIA)
|
self.set_state(PaymentIdentifierState.MERCHANT_NOTIFY)
|
||||||
elif self.lnurl:
|
elif self.lnurl:
|
||||||
data = await request_lnurl(self.lnurl)
|
data = await request_lnurl(self.lnurl)
|
||||||
self.lnurl_data = data
|
self.lnurl_data = data
|
||||||
@@ -356,11 +362,11 @@ class PaymentIdentifier(Logger):
|
|||||||
|
|
||||||
def finalize(self, *, amount_sat: int = 0, comment: str = None, on_finished: Callable = None):
|
def finalize(self, *, amount_sat: int = 0, comment: str = None, on_finished: Callable = None):
|
||||||
assert self._state == PaymentIdentifierState.LNURLP_FINALIZE
|
assert self._state == PaymentIdentifierState.LNURLP_FINALIZE
|
||||||
coro = self.do_finalize(amount_sat, comment, on_finished=on_finished)
|
coro = self._do_finalize(amount_sat, comment, on_finished=on_finished)
|
||||||
asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
||||||
|
|
||||||
@log_exceptions
|
@log_exceptions
|
||||||
async def do_finalize(self, amount_sat: int = None, comment: str = None, on_finished: Callable = None):
|
async def _do_finalize(self, amount_sat: int = None, comment: str = None, on_finished: Callable = None):
|
||||||
from .invoices import Invoice
|
from .invoices import Invoice
|
||||||
try:
|
try:
|
||||||
if not self.lnurl_data:
|
if not self.lnurl_data:
|
||||||
@@ -399,6 +405,32 @@ class PaymentIdentifier(Logger):
|
|||||||
if on_finished:
|
if on_finished:
|
||||||
on_finished(self)
|
on_finished(self)
|
||||||
|
|
||||||
|
def notify_merchant(self, *, tx: 'Transaction' = None, refund_address: str = None, on_finished: 'Callable' = None):
|
||||||
|
assert self._state == PaymentIdentifierState.MERCHANT_NOTIFY
|
||||||
|
assert tx
|
||||||
|
coro = self._do_notify_merchant(tx, refund_address, on_finished=on_finished)
|
||||||
|
asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
||||||
|
|
||||||
|
@log_exceptions
|
||||||
|
async def _do_notify_merchant(self, tx, refund_address, *, on_finished: 'Callable'):
|
||||||
|
try:
|
||||||
|
if not self.bip70_data:
|
||||||
|
self.set_state(PaymentIdentifierState.ERROR)
|
||||||
|
return
|
||||||
|
|
||||||
|
ack_status, ack_msg = await self.bip70_data.send_payment_and_receive_paymentack(tx.serialize(), refund_address)
|
||||||
|
self.logger.info(f"Payment ACK: {ack_status}. Ack message: {ack_msg}")
|
||||||
|
self.merchant_ack_status = ack_status
|
||||||
|
self.merchant_ack_message = ack_msg
|
||||||
|
self.set_state(PaymentIdentifierState.MERCHANT_ACK)
|
||||||
|
except Exception as e:
|
||||||
|
self.error = str(e)
|
||||||
|
self.logger.error(repr(e))
|
||||||
|
self.set_state(PaymentIdentifierState.MERCHANT_ERROR)
|
||||||
|
finally:
|
||||||
|
if on_finished:
|
||||||
|
on_finished(self)
|
||||||
|
|
||||||
def get_onchain_outputs(self, amount):
|
def get_onchain_outputs(self, amount):
|
||||||
if self.bip70:
|
if self.bip70:
|
||||||
return self.bip70_data.get_outputs()
|
return self.bip70_data.get_outputs()
|
||||||
@@ -609,13 +641,6 @@ class PaymentIdentifier(Logger):
|
|||||||
return self.bip70_data.has_expired()
|
return self.bip70_data.has_expired()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@log_exceptions
|
|
||||||
async def round_3(self, tx, refund_address, *, on_success):
|
|
||||||
if self.bip70:
|
|
||||||
ack_status, ack_msg = await self.bip70.send_payment_and_receive_paymentack(tx.serialize(), refund_address)
|
|
||||||
self.logger.info(f"Payment ACK: {ack_status}. Ack message: {ack_msg}")
|
|
||||||
on_success(self)
|
|
||||||
|
|
||||||
def get_invoice(self, amount_sat, message):
|
def get_invoice(self, amount_sat, message):
|
||||||
from .invoices import Invoice
|
from .invoices import Invoice
|
||||||
if self.is_lightning():
|
if self.is_lightning():
|
||||||
|
|||||||
Reference in New Issue
Block a user