From b472b4928c26c52063bc053b650fabbe68c53f7b Mon Sep 17 00:00:00 2001 From: Reckless_Satoshi Date: Fri, 7 Jan 2022 11:22:07 -0800 Subject: [PATCH] More logics, bug hunt --- api/lightning.py | 22 +++++++++++++--------- api/logics.py | 31 +++++++++++++++++++++++-------- api/models.py | 2 +- api/views.py | 4 ++-- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/api/lightning.py b/api/lightning.py index cf66a12f..a10f258b 100644 --- a/api/lightning.py +++ b/api/lightning.py @@ -22,32 +22,36 @@ class LNNode(): return invoice, payment_hash, expires_at - def validate_hodl_invoice_locked(): + def validate_hodl_invoice_locked(payment_hash): '''Generates hodl invoice to publish an order''' return True - def validate_ln_invoice(invoice): # num_satoshis + def validate_ln_invoice(invoice, num_satoshis): # num_satoshis '''Checks if the submited LN invoice is as expected''' valid = True - num_satoshis = 50000 # TODO decrypt and confirm sats are as expected + context = None description = 'Placeholder desc' # TODO decrypt from LN invoice - payment_hash = '567126' # TODO decrypt + payment_hash = '567&*GIHU126' # TODO decrypt expires_at = timezone.now() # TODO decrypt - return valid, num_satoshis, description, payment_hash, expires_at + return valid, context, description, payment_hash, expires_at - def pay_buyer_invoice(invoice): - '''Sends sats to buyer''' + def pay_invoice(invoice): + '''Sends sats to buyer, or cancelinvoices''' return True - def charge_hodl_htlcs(invoice): + def settle_hodl_htlcs(payment_hash): '''Charges a LN hodl invoice''' return True - def free_hodl_htlcs(invoice): + def return_hodl_htlcs(payment_hash): '''Returns sats''' return True + def double_check_htlc_is_settled(payment_hash): + ''' Just as it sounds. Better safe than sorry!''' + return True + diff --git a/api/logics.py b/api/logics.py index 5a8afe12..19dd971b 100644 --- a/api/logics.py +++ b/api/logics.py @@ -87,10 +87,19 @@ class Logics(): @classmethod def update_invoice(cls, order, user, invoice): - is_valid_invoice, num_satoshis, description, payment_hash, expires_at = LNNode.validate_ln_invoice(invoice) - # only user is the buyer and a valid LN invoice - if not (cls.is_buyer(order, user) or is_valid_invoice): - return False, {'bad_request':'Invalid Lightning Network Invoice. It starts by LNTB...'} + + # only the buyer can post a buyer invoice + if not cls.is_buyer(order, user): + return False, {'bad_request':'Only the buyer of this order can provide a buyer invoice.'} + if not order.taker_bond: + return False, {'bad_request':'Wait for your order to be taken.'} + if not (order.taker_bond.status == order.maker_bond.status == LNPayment.Status.LOCKED): + return False, {'bad_request':'You cannot a invoice while bonds are not posted.'} + + num_satoshis = cls.buyer_invoice_amount(order, user)[1]['invoice_amount'] + valid, context, description, payment_hash, expires_at = LNNode.validate_ln_invoice(invoice, num_satoshis) + if not valid: + return False, context order.buyer_invoice, _ = LNPayment.objects.update_or_create( concept = LNPayment.Concepts.PAYBUYER, @@ -150,7 +159,7 @@ class Logics(): return True, None @classmethod - def cancel_order(cls, order, user, state): + def cancel_order(cls, order, user, state=None): # 1) When maker cancels before bond '''The order never shows up on the book and order @@ -315,8 +324,8 @@ class Logics(): @classmethod def confirm_fiat(cls, order, user): ''' If Order is in the CHAT states: - If user is buyer: mark the FIAT SENT andettle escrow! - If User is the seller and FIAT was already sent: Pay buyer invoice!''' + If user is buyer: mark FIAT SENT and settle escrow! + If User is the seller and FIAT is SENT: Pay buyer invoice!''' if order.status == Order.Status.CHA or order.status == Order.Status.FSE: # TODO Alternatively, if all collateral is locked? test out @@ -334,7 +343,13 @@ class Logics(): # Double check the escrow is settled. if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash): - if cls.pay_buyer_invoice(order): # KEY LINE - PAYS THE BUYER !! + + # Make sure the trade escrow is at least as big as the buyer invoice + if order.trade_escrow.num_satoshis <= order.buyer_invoice.num_satoshis: + return False, {'bad_request':'Woah, something broke badly. Report in the public channels, or open a Github Issue.'} + + # Double check the trade escrow is settled + elif cls.pay_buyer_invoice(order): # KEY LINE - PAYS THE BUYER !! order.status = Order.Status.PAY order.buyer_invoice.status = LNPayment.Status.PAYING else: diff --git a/api/models.py b/api/models.py index 4f818b62..054381c9 100644 --- a/api/models.py +++ b/api/models.py @@ -137,7 +137,7 @@ class Order(models.Model): def __str__(self): # Make relational back to ORDER - return (f'Order {self.id}: {self.Types(self.type).label} BTC for {self.amount} {self.Currencies(self.currency).label}') + return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.Currencies(self.currency).label}') @receiver(pre_delete, sender=Order) def delelete_HTLCs_at_order_deletion(sender, instance, **kwargs): diff --git a/api/views.py b/api/views.py index 71d5b2e8..8ac2fd3e 100644 --- a/api/views.py +++ b/api/views.py @@ -128,13 +128,13 @@ class OrderView(viewsets.ViewSet): # If both bonds are locked, participants can see the trade in sats is also final. if order.taker_bond: - if order.maker_bond.status == order.taker_bond.status == order.trade_escrow.status == LNPayment.Status.LOCKED: + if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED: # Seller sees the amount he pays if data['is_seller']: data['trade_satoshis'] = order.last_satoshis # Buyer sees the amount he receives elif data['is_buyer']: - data['trade_satoshis'] = order.last_satoshis * (1-FEE) + data['trade_satoshis'] = Logics.buyer_invoice_amount(order, request.user)[1]['invoice_amount'] # 5) If status is 'waiting for maker bond' and user is MAKER, reply with a MAKER HODL invoice. if order.status == Order.Status.WFB and data['is_maker']: