mirror of
https://github.com/RoboSats/robosats.git
synced 2025-02-20 12:19:00 +00:00
Add more api logics
The workflow is actually more complex than I though. In fact the whole scope of the project greatly surpass my expectation of "weekend project". Want to lay down something functional even if buggy and ugly, I'm a bad coder but this will work out!
This commit is contained in:
parent
6a1a906bea
commit
8a55383761
125
api/logics.py
125
api/logics.py
@ -29,18 +29,18 @@ class Logics():
|
||||
'''Checks if the user is already partipant of an order'''
|
||||
queryset = Order.objects.filter(maker=user)
|
||||
if queryset.exists():
|
||||
return False, {'Bad Request':'You are already maker of an order'}
|
||||
return False, {'bad_request':'You are already maker of an order'}
|
||||
queryset = Order.objects.filter(taker=user)
|
||||
if queryset.exists():
|
||||
return False, {'Bad Request':'You are already taker of an order'}
|
||||
return False, {'bad_request':'You are already taker of an order'}
|
||||
return True, None
|
||||
|
||||
def validate_order_size(order):
|
||||
'''Checks if order is withing limits at t0'''
|
||||
if order.t0_satoshis > MAX_TRADE:
|
||||
return False, {'Bad_request': 'Your order is too big. It is worth {order.t0_satoshis} now, max is {MAX_TRADE}'}
|
||||
return False, {'bad_request': f'Your order is too big. It is worth {order.t0_satoshis} now. But maximum is {MAX_TRADE}'}
|
||||
if order.t0_satoshis < MIN_TRADE:
|
||||
return False, {'Bad_request': 'Your order is too small. It is worth {order.t0_satoshis} now, min is {MIN_TRADE}'}
|
||||
return False, {'bad_request': f'Your order is too small. It is worth {order.t0_satoshis} now. But minimum is {MIN_TRADE}'}
|
||||
return True, None
|
||||
|
||||
def take(order, user):
|
||||
@ -64,11 +64,12 @@ class Logics():
|
||||
satoshis_now = order.satoshis
|
||||
else:
|
||||
# TODO Add fallback Public APIs and error handling
|
||||
# Think about polling price data in a different way (e.g. store locally every t seconds)
|
||||
market_prices = requests.get(MARKET_PRICE_API).json()
|
||||
exchange_rate = float(market_prices[Order.Currencies(order.currency).label]['last'])
|
||||
satoshis_now = ((float(order.amount) * 1+float(order.premium)) / exchange_rate) * 100*1000*1000
|
||||
|
||||
return satoshis_now
|
||||
return int(satoshis_now)
|
||||
|
||||
def order_expires(order):
|
||||
order.status = Order.Status.EXP
|
||||
@ -76,6 +77,16 @@ class Logics():
|
||||
order.taker = None
|
||||
order.save()
|
||||
|
||||
@classmethod
|
||||
def buyer_invoice_amount(cls, order, user):
|
||||
''' Computes buyer invoice amount. Uses order.last_satoshis,
|
||||
that is the final trade amount set at Taker Bond time'''
|
||||
|
||||
if cls.is_buyer(order, user):
|
||||
invoice_amount = int(order.last_satoshis * (1-FEE)) # Trading FEE is charged here.
|
||||
|
||||
return True, {'invoice_amount': invoice_amount}
|
||||
|
||||
@classmethod
|
||||
def update_invoice(cls, order, user, invoice):
|
||||
is_valid_invoice, num_satoshis, description, payment_hash, expires_at = LNNode.validate_ln_invoice(invoice)
|
||||
@ -117,12 +128,26 @@ class Logics():
|
||||
order.save()
|
||||
return True, None
|
||||
|
||||
|
||||
@classmethod
|
||||
def rate_counterparty(cls, order, user, rating):
|
||||
# if maker, rates taker
|
||||
if order.maker == user:
|
||||
order.taker.profile.total_ratings = order.taker.profile.total_ratings + 1
|
||||
last_ratings = list(order.taker.profile.last_ratings).append(rating)
|
||||
order.taker.profile.total_ratings = sum(last_ratings) / len(last_ratings)
|
||||
# if taker, rates maker
|
||||
if order.taker == user:
|
||||
order.maker.profile.total_ratings = order.maker.profile.total_ratings + 1
|
||||
last_ratings = list(order.maker.profile.last_ratings).append(rating)
|
||||
order.maker.profile.total_ratings = sum(last_ratings) / len(last_ratings)
|
||||
|
||||
order.save()
|
||||
return True, None
|
||||
|
||||
@classmethod
|
||||
def cancel_order(cls, order, user, state):
|
||||
|
||||
# 1) When maker cancels before bond
|
||||
|
||||
# 1) When maker cancels before bond
|
||||
'''The order never shows up on the book and order
|
||||
status becomes "cancelled". That's it.'''
|
||||
if order.status == Order.Status.WFB and order.maker == user:
|
||||
@ -140,12 +165,12 @@ class Logics():
|
||||
''' The order goes back to the book as public.
|
||||
LNPayment "order.taker_bond" is deleted() '''
|
||||
|
||||
# 4) When taker or maker cancel after bond
|
||||
# 4) When taker or maker cancel after bond (before escrow)
|
||||
'''The order goes into cancelled status if maker cancels.
|
||||
The order goes into the public book if taker cancels.
|
||||
In both cases there is a small fee.'''
|
||||
|
||||
# 5) When trade collateral has been posted
|
||||
# 5) When trade collateral has been posted (after escrow)
|
||||
'''Always goes to cancelled status. Collaboration is needed.
|
||||
When a user asks for cancel, 'order.is_pending_cancel' goes True.
|
||||
When the second user asks for cancel. Order is totally cancelled.
|
||||
@ -154,22 +179,23 @@ class Logics():
|
||||
else:
|
||||
return False, {'bad_request':'You cannot cancel this order'}
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def gen_maker_hodl_invoice(cls, order, user):
|
||||
|
||||
# Do not gen and delete if order is more than 5 minutes old
|
||||
# Do not gen and cancel if order is more than 5 minutes old
|
||||
if order.expires_at < timezone.now():
|
||||
cls.order_expires(order)
|
||||
return False, {'Order expired':'cannot generate a bond invoice for an expired order. Make a new one.'}
|
||||
return False, {'bad_request':'Invoice expired. You did not confirm publishing the order in time. Make a new order.'}
|
||||
|
||||
# Return the previous invoice if there was one
|
||||
# Return the previous invoice if there was one and is still unpaid
|
||||
if order.maker_bond:
|
||||
return True, {'invoice':order.maker_bond.invoice,'bond_satoshis':order.maker_bond.num_satoshis}
|
||||
if order.maker_bond.status == LNPayment.Status.INVGEN:
|
||||
return True, {'bond_invoice':order.maker_bond.invoice,'bond_satoshis':order.maker_bond.num_satoshis}
|
||||
else:
|
||||
return False, None
|
||||
|
||||
order.satoshis_now = cls.satoshis_now(order)
|
||||
bond_satoshis = int(order.satoshis_now * BOND_SIZE)
|
||||
order.last_satoshis = cls.satoshis_now(order)
|
||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
||||
description = f'RoboSats - Publishing {str(order)} - This bond will return to you if you do not cheat.'
|
||||
|
||||
# Gen HODL Invoice
|
||||
@ -188,22 +214,27 @@ class Logics():
|
||||
expires_at = expires_at)
|
||||
|
||||
order.save()
|
||||
return True, {'invoice':invoice,'bond_satoshis':bond_satoshis}
|
||||
return True, {'bond_invoice':invoice,'bond_satoshis':bond_satoshis}
|
||||
|
||||
@classmethod
|
||||
def gen_taker_hodl_invoice(cls, order, user):
|
||||
|
||||
# Do not gen and cancel if a taker invoice is there and older than 2 minutes
|
||||
# Do not gen and cancel if a taker invoice is there and older than X minutes and unpaid still
|
||||
if order.taker_bond:
|
||||
if order.taker_bond.created_at > (timezone.now()+timedelta(minutes=EXP_TAKER_BOND_INVOICE)):
|
||||
cls.cancel_order(order, user, 3) # State 3, cancel order before taker bond
|
||||
return False, {'Invoice expired':'You did not confirm taking the order in time.'}
|
||||
# Check if status is INVGEN and still not expired
|
||||
if order.taker_bond.status == LNPayment.Status.INVGEN:
|
||||
if order.taker_bond.created_at > (timezone.now()+timedelta(minutes=EXP_TAKER_BOND_INVOICE)):
|
||||
cls.cancel_order(order, user, 3) # State 3, cancel order before taker bond
|
||||
return False, {'bad_request':'Invoice expired. You did not confirm taking the order in time.'}
|
||||
# Return the previous invoice there was with INVGEN status
|
||||
else:
|
||||
return True, {'bond_invoice':order.taker_bond.invoice,'bond_satoshis':order.taker_bond.num_satoshis}
|
||||
# Invoice exists, but was already locked or settled
|
||||
else:
|
||||
# Return the previous invoice if there was one
|
||||
return True, {'invoice':order.taker_bond.invoice,'bond_satoshis':order.taker_bond.num_satoshis}
|
||||
return False, None
|
||||
|
||||
order.satoshis_now = cls.satoshis_now(order)
|
||||
bond_satoshis = int(order.satoshis_now * BOND_SIZE)
|
||||
order.last_satoshis = cls.satoshis_now(order) # LOCKS THE AMOUNT OF SATOSHIS FOR THE TRADE
|
||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
||||
description = f'RoboSats - Taking {str(order)} - This bond will return to you if you do not cheat.'
|
||||
|
||||
# Gen HODL Invoice
|
||||
@ -222,4 +253,42 @@ class Logics():
|
||||
expires_at = expires_at)
|
||||
|
||||
order.save()
|
||||
return True, {'invoice':invoice,'bond_satoshis': bond_satoshis}
|
||||
return True, {'bond_invoice':invoice,'bond_satoshis': bond_satoshis}
|
||||
|
||||
@classmethod
|
||||
def gen_escrow_hodl_invoice(cls, order, user):
|
||||
|
||||
# Do not generate and cancel if an invoice is there and older than X minutes and unpaid still
|
||||
if order.trade_escrow:
|
||||
# Check if status is INVGEN and still not expired
|
||||
if order.taker_bond.status == LNPayment.Status.INVGEN:
|
||||
if order.taker_bond.created_at > (timezone.now()+timedelta(minutes=EXP_TRADE_ESCR_INVOICE)): # Expired
|
||||
cls.cancel_order(order, user, 4) # State 4, cancel order before trade escrow locked
|
||||
return False, {'bad_request':'Invoice expired. You did not lock the trade escrow in time.'}
|
||||
# Return the previous invoice there was with INVGEN status
|
||||
else:
|
||||
return True, {'escrow_invoice':order.trade_escrow.invoice,'escrow_satoshis':order.trade_escrow.num_satoshis}
|
||||
# Invoice exists, but was already locked or settled
|
||||
else:
|
||||
return False, None # Does not return any context of a healthy locked escrow
|
||||
|
||||
escrow_satoshis = order.last_satoshis # Trade sats amount was fixed at the time of taker bond generation (order.last_satoshis)
|
||||
description = f'RoboSats - Escrow amount for {str(order)} - This escrow will be released to the buyer once you confirm you received the fiat.'
|
||||
|
||||
# Gen HODL Invoice
|
||||
invoice, payment_hash, expires_at = LNNode.gen_hodl_invoice(escrow_satoshis, description, ESCROW_EXPIRY*3600)
|
||||
|
||||
order.taker_bond = LNPayment.objects.create(
|
||||
concept = LNPayment.Concepts.TRESCROW,
|
||||
type = LNPayment.Types.HODL,
|
||||
sender = user,
|
||||
receiver = User.objects.get(username=ESCROW_USERNAME),
|
||||
invoice = invoice,
|
||||
status = LNPayment.Status.INVGEN,
|
||||
num_satoshis = escrow_satoshis,
|
||||
description = description,
|
||||
payment_hash = payment_hash,
|
||||
expires_at = expires_at)
|
||||
|
||||
order.save()
|
||||
return True, {'escrow_invoice':invoice,'escrow_satoshis': escrow_satoshis}
|
@ -27,18 +27,18 @@ class LNPayment(models.Model):
|
||||
|
||||
class Concepts(models.IntegerChoices):
|
||||
MAKEBOND = 0, 'Maker bond'
|
||||
TAKEBOND = 1, 'Taker-buyer bond'
|
||||
TAKEBOND = 1, 'Taker bond'
|
||||
TRESCROW = 2, 'Trade escrow'
|
||||
PAYBUYER = 3, 'Payment to buyer'
|
||||
|
||||
class Status(models.IntegerChoices):
|
||||
INVGEN = 0, 'Hodl invoice was generated'
|
||||
LOCKED = 1, 'Hodl invoice has HTLCs locked'
|
||||
SETLED = 2, 'Invoice settled'
|
||||
RETNED = 3, 'Hodl invoice was returned'
|
||||
MISSNG = 4, 'Buyer invoice is missing'
|
||||
VALIDI = 5, 'Buyer invoice is valid'
|
||||
INFAIL = 6, 'Buyer invoice routing failed'
|
||||
INVGEN = 0, 'Generated'
|
||||
LOCKED = 1, 'Locked'
|
||||
SETLED = 2, 'Settled'
|
||||
RETNED = 3, 'Returned'
|
||||
MISSNG = 4, 'Missing'
|
||||
VALIDI = 5, 'Valid'
|
||||
INFAIL = 6, 'Failed routing'
|
||||
|
||||
# payment use details
|
||||
type = models.PositiveSmallIntegerField(choices=Types.choices, null=False, default=Types.HODL)
|
||||
@ -59,8 +59,7 @@ class LNPayment(models.Model):
|
||||
receiver = models.ForeignKey(User, related_name='receiver', on_delete=models.CASCADE, null=True, default=None)
|
||||
|
||||
def __str__(self):
|
||||
# Make relational back to ORDER
|
||||
return (f'HTLC {self.id}: {self.Concepts(self.concept).label}')
|
||||
return (f'HTLC {self.id}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}')
|
||||
|
||||
class Order(models.Model):
|
||||
|
||||
@ -74,16 +73,16 @@ class Order(models.Model):
|
||||
ETH = 3, 'ETH'
|
||||
|
||||
class Status(models.IntegerChoices):
|
||||
WFB = 0, 'Waiting for maker bond'
|
||||
PUB = 1, 'Public'
|
||||
DEL = 2, 'Deleted'
|
||||
TAK = 3, 'Waiting for taker bond'
|
||||
UCA = 4, 'Cancelled'
|
||||
WF2 = 5, 'Waiting for trade collateral and buyer invoice'
|
||||
WFE = 6, 'Waiting only for seller trade collateral'
|
||||
WFI = 7, 'Waiting only for buyer invoice'
|
||||
CHA = 8, 'Sending fiat - In chatroom'
|
||||
CCA = 9, 'Collaboratively cancelled'
|
||||
WFB = 0, 'Waiting for maker bond'
|
||||
PUB = 1, 'Public'
|
||||
DEL = 2, 'Deleted'
|
||||
TAK = 3, 'Waiting for taker bond'
|
||||
UCA = 4, 'Cancelled'
|
||||
WF2 = 5, 'Waiting for trade collateral and buyer invoice'
|
||||
WFE = 6, 'Waiting only for seller trade collateral'
|
||||
WFI = 7, 'Waiting only for buyer invoice'
|
||||
CHA = 8, 'Sending fiat - In chatroom'
|
||||
CCA = 9, 'Collaboratively cancelled'
|
||||
FSE = 10, 'Fiat sent - In chatroom'
|
||||
FCO = 11, 'Fiat confirmed'
|
||||
SUC = 12, 'Sucessfully settled'
|
||||
@ -130,7 +129,7 @@ class Order(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
# Make relational back to ORDER
|
||||
return (f'Order {self.id}: {self.Types(self.type).label} {"{:,}".format(self.t0_satoshis)} Sats for {self.Currencies(self.currency).label}')
|
||||
return (f'Order {self.id}: {self.Types(self.type).label} BTC for {self.amount} {self.Currencies(self.currency).label}')
|
||||
|
||||
@receiver(pre_delete, sender=Order)
|
||||
def delelete_HTLCs_at_order_deletion(sender, instance, **kwargs):
|
||||
|
144
api/views.py
144
api/views.py
@ -7,7 +7,7 @@ from django.contrib.auth import authenticate, login, logout
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from .serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer
|
||||
from .models import Order
|
||||
from .models import LNPayment, Order
|
||||
from .logics import Logics
|
||||
|
||||
from .nick_generator.nick_generator import NickGenerator
|
||||
@ -74,75 +74,100 @@ class OrderView(viewsets.ViewSet):
|
||||
lookup_url_kwarg = 'order_id'
|
||||
|
||||
def get(self, request, format=None):
|
||||
'''
|
||||
Full trade pipeline takes place while looking/refreshing the order page.
|
||||
'''
|
||||
order_id = request.GET.get(self.lookup_url_kwarg)
|
||||
|
||||
if order_id == None:
|
||||
return Response({'Bad Request':'Order ID parameter not found in request'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response({'bad_request':'Order ID parameter not found in request'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
order = Order.objects.filter(id=order_id)
|
||||
|
||||
# check if exactly one order is found in the db
|
||||
if len(order) == 1 :
|
||||
order = order[0]
|
||||
if len(order) != 1 :
|
||||
return Response({'bad_request':'Invalid Order Id'}, status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# This is our order.
|
||||
order = order[0]
|
||||
|
||||
# 1) If order expired
|
||||
if order.status == Order.Status.EXP:
|
||||
return Response({'bad_request':'This order has expired'},status.HTTP_400_BAD_REQUEST)
|
||||
# 1) If order expired
|
||||
if order.status == Order.Status.EXP:
|
||||
return Response({'bad_request':'This order has expired'},status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 2) If order cancelled
|
||||
if order.status == Order.Status.UCA:
|
||||
return Response({'bad_request':'This order has been cancelled by the maker'},status.HTTP_400_BAD_REQUEST)
|
||||
if order.status == Order.Status.CCA:
|
||||
return Response({'bad_request':'This order has been cancelled collaborativelly'},status.HTTP_400_BAD_REQUEST)
|
||||
# 2) If order cancelled
|
||||
if order.status == Order.Status.UCA:
|
||||
return Response({'bad_request':'This order has been cancelled by the maker'},status.HTTP_400_BAD_REQUEST)
|
||||
if order.status == Order.Status.CCA:
|
||||
return Response({'bad_request':'This order has been cancelled collaborativelly'},status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
data = ListOrderSerializer(order).data
|
||||
data = ListOrderSerializer(order).data
|
||||
|
||||
# Add booleans if user is maker, taker, partipant, buyer or seller
|
||||
data['is_maker'] = order.maker == request.user
|
||||
data['is_taker'] = order.taker == request.user
|
||||
data['is_participant'] = data['is_maker'] or data['is_taker']
|
||||
|
||||
# 3) If not a participant and order is not public, forbid.
|
||||
if not data['is_participant'] and order.status != Order.Status.PUB:
|
||||
return Response({'bad_request':'Not allowed to see this order'},status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 4) Non participants can view details (but only if PUB)
|
||||
elif not data['is_participant'] and order.status != Order.Status.PUB:
|
||||
return Response(data, status=status.HTTP_200_OK)
|
||||
# Add booleans if user is maker, taker, partipant, buyer or seller
|
||||
data['is_maker'] = order.maker == request.user
|
||||
data['is_taker'] = order.taker == request.user
|
||||
data['is_participant'] = data['is_maker'] or data['is_taker']
|
||||
|
||||
# 3) If not a participant and order is not public, forbid.
|
||||
if not data['is_participant'] and order.status != Order.Status.PUB:
|
||||
return Response({'bad_request':'You are not allowed to see this order'},status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# 4) Non participants can view details (but only if PUB)
|
||||
elif not data['is_participant'] and order.status != Order.Status.PUB:
|
||||
return Response(data, status=status.HTTP_200_OK)
|
||||
|
||||
# For participants add position side, nicks and status as message
|
||||
data['is_buyer'] = Logics.is_buyer(order,request.user)
|
||||
data['is_seller'] = Logics.is_seller(order,request.user)
|
||||
data['maker_nick'] = str(order.maker)
|
||||
data['taker_nick'] = str(order.taker)
|
||||
data['status_message'] = Order.Status(order.status).label
|
||||
# For participants add position side, nicks and status as message
|
||||
data['is_buyer'] = Logics.is_buyer(order,request.user)
|
||||
data['is_seller'] = Logics.is_seller(order,request.user)
|
||||
data['maker_nick'] = str(order.maker)
|
||||
data['taker_nick'] = str(order.taker)
|
||||
data['status_message'] = Order.Status(order.status).label
|
||||
|
||||
# 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']:
|
||||
valid, context = Logics.gen_maker_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 6) If status is 'waiting for taker bond' and user is TAKER, reply with a TAKER HODL invoice.
|
||||
elif order.status == Order.Status.TAK and data['is_taker']:
|
||||
valid, context = Logics.gen_taker_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 7) If status is 'WF2'or'WTC' and user is Seller, reply with an ESCROW HODL invoice.
|
||||
elif (order.status == Order.Status.WF2 or order.status == Order.Status.WFE) and data['is_seller']:
|
||||
valid, context = Logics.gen_seller_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
# 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']:
|
||||
valid, context = Logics.gen_maker_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 6) If status is 'waiting for taker bond' and user is TAKER, reply with a TAKER HODL invoice.
|
||||
elif order.status == Order.Status.TAK and data['is_taker']:
|
||||
valid, context = Logics.gen_taker_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 7) If status is 'WF2'or'WTC'
|
||||
elif (order.status == Order.Status.WF2 or order.status == Order.Status.WFE):
|
||||
|
||||
return Response(data, status.HTTP_200_OK)
|
||||
return Response({'Order Not Found':'Invalid Order Id'}, status.HTTP_404_NOT_FOUND)
|
||||
# If the two bonds are locked
|
||||
if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED:
|
||||
|
||||
# 7.a) And if user is Seller, reply with an ESCROW HODL invoice.
|
||||
if data['is_seller']:
|
||||
valid, context = Logics.gen_escrow_hodl_invoice(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 7.b) If user is Buyer, reply with an AMOUNT so he can send the buyer invoice.
|
||||
elif data['is_buyer']:
|
||||
valid, context = Logics.buyer_invoice_amount(order, request.user)
|
||||
if valid:
|
||||
data = {**data, **context}
|
||||
else:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 8) If status is 'CHA'or '' or '' and all HTLCS are in LOCKED
|
||||
elif order.status == Order.Status.CHA: # TODO Add the other status
|
||||
if order.maker_bond.status == order.taker_bond.status == order.trade_escrow.status == LNPayment.Status.LOCKED:
|
||||
# add whether a collaborative cancel is pending
|
||||
data['pending_cancel'] = order.is_pending_cancel
|
||||
|
||||
return Response(data, status.HTTP_200_OK)
|
||||
|
||||
def take_update_confirm_dispute_cancel(self, request, format=None):
|
||||
'''
|
||||
@ -177,7 +202,7 @@ class OrderView(viewsets.ViewSet):
|
||||
|
||||
# 3) If action is cancel
|
||||
elif action == 'cancel':
|
||||
valid, context = Logics.cancel_order(order,request.user,invoice)
|
||||
valid, context = Logics.cancel_order(order,request.user)
|
||||
if not valid: return Response(context,status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 4) If action is confirm
|
||||
@ -190,11 +215,12 @@ class OrderView(viewsets.ViewSet):
|
||||
|
||||
# 6) If action is dispute
|
||||
elif action == 'rate' and rating:
|
||||
pass
|
||||
valid, context = Logics.rate_counterparty(order,request.user, rating)
|
||||
if not valid: return Response(context,status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# If nothing... something else is going on. Probably not allowed!
|
||||
else:
|
||||
return Response({'bad_request':'Not allowed'})
|
||||
return Response({'bad_request':'The Robotic Satoshis working in the warehouse did not understand you'})
|
||||
|
||||
return self.get(request)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Paper, Button , Grid, Typography, TextField, Select, FormHelperText, MenuItem, FormControl, Radio, FormControlLabel, RadioGroup, Menu} from "@material-ui/core"
|
||||
import { Paper, Alert, AlertTitle, Button , Grid, Typography, TextField, Select, FormHelperText, MenuItem, FormControl, Radio, FormControlLabel, RadioGroup, Menu} from "@material-ui/core"
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
function getCookie(name) {
|
||||
@ -104,7 +104,8 @@ export default class MakerPage extends Component {
|
||||
};
|
||||
fetch("/api/make/",requestOptions)
|
||||
.then((response) => response.json())
|
||||
.then((data) => (console.log(data) & this.props.history.push('/order/' + data.id)));
|
||||
.then((data) => (this.setState({badRequest:data.bad_request})
|
||||
& (data.id ? this.props.history.push('/order/' + data.id) :"")));
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -242,6 +243,13 @@ export default class MakerPage extends Component {
|
||||
<Button color="primary" variant="contained" onClick={this.handleCreateOfferButtonPressed} >
|
||||
Create Order
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={12} align="center">
|
||||
{this.state.badRequest ?
|
||||
<Typography component="subtitle2" variant="subtitle2" color="secondary">
|
||||
{this.state.badRequest} <br/>
|
||||
</Typography>
|
||||
: ""}
|
||||
<Typography component="subtitle2" variant="subtitle2">
|
||||
<div align='center'>
|
||||
Create a BTC {this.state.type==0 ? "buy":"sell"} order for {this.state.amount} {this.state.currencyCode}
|
||||
|
@ -68,6 +68,7 @@ export default class OrderPage extends Component {
|
||||
isBuyer:data.buyer,
|
||||
isSeller:data.seller,
|
||||
expiresAt:data.expires_at,
|
||||
badRequest:data.bad_request,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user