mirror of
https://github.com/RoboSats/robosats.git
synced 2025-02-12 08:19:02 +00:00
Work frontend trade pipeline
This commit is contained in:
parent
fb846c91d8
commit
8e5233267f
@ -1,3 +1,6 @@
|
|||||||
|
# import codecs, grpc, os
|
||||||
|
# import lightning_pb2 as lnrpc, lightning_pb2_grpc as lightningstub
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -13,8 +16,15 @@ class LNNode():
|
|||||||
Place holder functions to interact with Lightning Node
|
Place holder functions to interact with Lightning Node
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def gen_hodl_invoice(num_satoshis, description, expiry):
|
# macaroon = codecs.encode(open('LND_DIR/data/chain/bitcoin/simnet/admin.macaroon', 'rb').read(), 'hex')
|
||||||
'''Generates hodl invoice to publish an order'''
|
# os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
|
||||||
|
# cert = open('LND_DIR/tls.cert', 'rb').read()
|
||||||
|
# ssl_creds = grpc.ssl_channel_credentials(cert)
|
||||||
|
# channel = grpc.secure_channel('localhost:10009', ssl_creds)
|
||||||
|
# stub = lightningstub.LightningStub(channel)
|
||||||
|
|
||||||
|
def gen_hold_invoice(num_satoshis, description, expiry):
|
||||||
|
'''Generates hold invoice to publish an order'''
|
||||||
# TODO
|
# TODO
|
||||||
invoice = ''.join(random.choices(string.ascii_uppercase + string.digits, k=80)) #FIX
|
invoice = ''.join(random.choices(string.ascii_uppercase + string.digits, k=80)) #FIX
|
||||||
payment_hash = ''.join(random.choices(string.ascii_uppercase + string.digits, k=40)) #FIX
|
payment_hash = ''.join(random.choices(string.ascii_uppercase + string.digits, k=40)) #FIX
|
||||||
@ -22,12 +32,46 @@ class LNNode():
|
|||||||
|
|
||||||
return invoice, payment_hash, expires_at
|
return invoice, payment_hash, expires_at
|
||||||
|
|
||||||
def validate_hodl_invoice_locked(payment_hash):
|
def validate_hold_invoice_locked(payment_hash):
|
||||||
'''Generates hodl invoice to publish an order'''
|
'''Checks if hodl invoice is locked'''
|
||||||
|
|
||||||
|
# request = ln.InvoiceSubscription()
|
||||||
|
# When invoice is settled, return true. If time expires, return False.
|
||||||
|
# for invoice in stub.SubscribeInvoices(request):
|
||||||
|
# print(invoice)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def validate_ln_invoice(invoice, num_satoshis): # num_satoshis
|
def validate_ln_invoice(invoice, num_satoshis):
|
||||||
'''Checks if the submited LN invoice is as expected'''
|
'''Checks if the submited LN invoice is as expected'''
|
||||||
|
|
||||||
|
# request = lnrpc.PayReqString(pay_req=invoice)
|
||||||
|
# response = stub.DecodePayReq(request, metadata=[('macaroon', macaroon)])
|
||||||
|
|
||||||
|
# # {
|
||||||
|
# # "destination": <string>,
|
||||||
|
# # "payment_hash": <string>,
|
||||||
|
# # "num_satoshis": <int64>,
|
||||||
|
# # "timestamp": <int64>,
|
||||||
|
# # "expiry": <int64>,
|
||||||
|
# # "description": <string>,
|
||||||
|
# # "description_hash": <string>,
|
||||||
|
# # "fallback_addr": <string>,
|
||||||
|
# # "cltv_expiry": <int64>,
|
||||||
|
# # "route_hints": <array RouteHint>,
|
||||||
|
# # "payment_addr": <bytes>,
|
||||||
|
# # "num_msat": <int64>,
|
||||||
|
# # "features": <array FeaturesEntry>,
|
||||||
|
# # }
|
||||||
|
|
||||||
|
# if not response['num_satoshis'] == num_satoshis:
|
||||||
|
# return False, {'bad_invoice':f'The invoice provided is not for {num_satoshis}. '}, None, None, None
|
||||||
|
# description = response['description']
|
||||||
|
# payment_hash = response['payment_hash']
|
||||||
|
# expires_at = timezone(response['expiry'])
|
||||||
|
# if payment_hash and expires_at > timezone.now():
|
||||||
|
# return True, None, description, payment_hash, expires_at
|
||||||
|
|
||||||
valid = True
|
valid = True
|
||||||
context = None
|
context = None
|
||||||
description = 'Placeholder desc' # TODO decrypt from LN invoice
|
description = 'Placeholder desc' # TODO decrypt from LN invoice
|
||||||
@ -40,11 +84,11 @@ class LNNode():
|
|||||||
'''Sends sats to buyer, or cancelinvoices'''
|
'''Sends sats to buyer, or cancelinvoices'''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def settle_hodl_htlcs(payment_hash):
|
def settle_hold_htlcs(payment_hash):
|
||||||
'''Charges a LN hodl invoice'''
|
'''Charges a LN hold invoice'''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def return_hodl_htlcs(payment_hash):
|
def return_hold_htlcs(payment_hash):
|
||||||
'''Returns sats'''
|
'''Returns sats'''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ class Logics():
|
|||||||
return False, {'bad_request':'You cannot cancel this order'}
|
return False, {'bad_request':'You cannot cancel this order'}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_maker_hodl_invoice(cls, order, user):
|
def gen_maker_hold_invoice(cls, order, user):
|
||||||
|
|
||||||
# Do not gen and cancel 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():
|
if order.expires_at < timezone.now():
|
||||||
@ -206,12 +206,12 @@ class Logics():
|
|||||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
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.'
|
description = f'RoboSats - Publishing {str(order)} - This bond will return to you if you do not cheat.'
|
||||||
|
|
||||||
# Gen HODL Invoice
|
# Gen hold Invoice
|
||||||
invoice, payment_hash, expires_at = LNNode.gen_hodl_invoice(bond_satoshis, description, BOND_EXPIRY*3600)
|
invoice, payment_hash, expires_at = LNNode.gen_hold_invoice(bond_satoshis, description, BOND_EXPIRY*3600)
|
||||||
|
|
||||||
order.maker_bond = LNPayment.objects.create(
|
order.maker_bond = LNPayment.objects.create(
|
||||||
concept = LNPayment.Concepts.MAKEBOND,
|
concept = LNPayment.Concepts.MAKEBOND,
|
||||||
type = LNPayment.Types.HODL,
|
type = LNPayment.Types.hold,
|
||||||
sender = user,
|
sender = user,
|
||||||
receiver = User.objects.get(username=ESCROW_USERNAME),
|
receiver = User.objects.get(username=ESCROW_USERNAME),
|
||||||
invoice = invoice,
|
invoice = invoice,
|
||||||
@ -225,7 +225,7 @@ class Logics():
|
|||||||
return True, {'bond_invoice':invoice,'bond_satoshis':bond_satoshis}
|
return True, {'bond_invoice':invoice,'bond_satoshis':bond_satoshis}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_taker_hodl_invoice(cls, order, user):
|
def gen_taker_hold_invoice(cls, order, user):
|
||||||
|
|
||||||
# Do not gen and cancel if a taker invoice is there and older than X minutes and unpaid still
|
# 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:
|
||||||
@ -245,12 +245,12 @@ class Logics():
|
|||||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
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.'
|
description = f'RoboSats - Taking {str(order)} - This bond will return to you if you do not cheat.'
|
||||||
|
|
||||||
# Gen HODL Invoice
|
# Gen hold Invoice
|
||||||
invoice, payment_hash, expires_at = LNNode.gen_hodl_invoice(bond_satoshis, description, BOND_EXPIRY*3600)
|
invoice, payment_hash, expires_at = LNNode.gen_hold_invoice(bond_satoshis, description, BOND_EXPIRY*3600)
|
||||||
|
|
||||||
order.taker_bond = LNPayment.objects.create(
|
order.taker_bond = LNPayment.objects.create(
|
||||||
concept = LNPayment.Concepts.TAKEBOND,
|
concept = LNPayment.Concepts.TAKEBOND,
|
||||||
type = LNPayment.Types.HODL,
|
type = LNPayment.Types.hold,
|
||||||
sender = user,
|
sender = user,
|
||||||
receiver = User.objects.get(username=ESCROW_USERNAME),
|
receiver = User.objects.get(username=ESCROW_USERNAME),
|
||||||
invoice = invoice,
|
invoice = invoice,
|
||||||
@ -267,7 +267,7 @@ class Logics():
|
|||||||
return True, {'bond_invoice':invoice,'bond_satoshis': bond_satoshis}
|
return True, {'bond_invoice':invoice,'bond_satoshis': bond_satoshis}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def gen_escrow_hodl_invoice(cls, order, user):
|
def gen_escrow_hold_invoice(cls, order, user):
|
||||||
# Do not generate and cancel if an invoice is there and older than X minutes and unpaid still
|
# Do not generate and cancel if an invoice is there and older than X minutes and unpaid still
|
||||||
if order.trade_escrow:
|
if order.trade_escrow:
|
||||||
# Check if status is INVGEN and still not expired
|
# Check if status is INVGEN and still not expired
|
||||||
@ -285,12 +285,12 @@ class Logics():
|
|||||||
escrow_satoshis = order.last_satoshis # Trade sats amount was fixed at the time of taker bond generation (order.last_satoshis)
|
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.'
|
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
|
# Gen hold Invoice
|
||||||
invoice, payment_hash, expires_at = LNNode.gen_hodl_invoice(escrow_satoshis, description, ESCROW_EXPIRY*3600)
|
invoice, payment_hash, expires_at = LNNode.gen_hold_invoice(escrow_satoshis, description, ESCROW_EXPIRY*3600)
|
||||||
|
|
||||||
order.trade_escrow = LNPayment.objects.create(
|
order.trade_escrow = LNPayment.objects.create(
|
||||||
concept = LNPayment.Concepts.TRESCROW,
|
concept = LNPayment.Concepts.TRESCROW,
|
||||||
type = LNPayment.Types.HODL,
|
type = LNPayment.Types.hold,
|
||||||
sender = user,
|
sender = user,
|
||||||
receiver = User.objects.get(username=ESCROW_USERNAME),
|
receiver = User.objects.get(username=ESCROW_USERNAME),
|
||||||
invoice = invoice,
|
invoice = invoice,
|
||||||
@ -307,7 +307,7 @@ class Logics():
|
|||||||
''' Settles the trade escrow HTLC'''
|
''' Settles the trade escrow HTLC'''
|
||||||
# TODO ERROR HANDLING
|
# TODO ERROR HANDLING
|
||||||
|
|
||||||
valid = LNNode.settle_hodl_htlcs(order.trade_escrow.payment_hash)
|
valid = LNNode.settle_hold_htlcs(order.trade_escrow.payment_hash)
|
||||||
return valid
|
return valid
|
||||||
|
|
||||||
def pay_buyer_invoice(order):
|
def pay_buyer_invoice(order):
|
||||||
@ -338,7 +338,7 @@ class Logics():
|
|||||||
return False, {'bad_request':'You cannot confirm to have received the fiat before it is confirmed to be sent by the buyer.'}
|
return False, {'bad_request':'You cannot confirm to have received the fiat before it is confirmed to be sent by the buyer.'}
|
||||||
|
|
||||||
# Make sure the trade escrow is at least as big as the buyer invoice
|
# 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:
|
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.'}
|
return False, {'bad_request':'Woah, something broke badly. Report in the public channels, or open a Github Issue.'}
|
||||||
|
|
||||||
# Double check the escrow is settled.
|
# Double check the escrow is settled.
|
||||||
|
@ -18,8 +18,8 @@ BOND_SIZE = float(config('BOND_SIZE'))
|
|||||||
class LNPayment(models.Model):
|
class LNPayment(models.Model):
|
||||||
|
|
||||||
class Types(models.IntegerChoices):
|
class Types(models.IntegerChoices):
|
||||||
NORM = 0, 'Regular invoice' # Only outgoing HTLCs will be regular invoices (Non-hodl)
|
NORM = 0, 'Regular invoice' # Only outgoing HTLCs will be regular invoices (Non-hold)
|
||||||
HODL = 1, 'Hodl invoice'
|
hold = 1, 'hold invoice'
|
||||||
|
|
||||||
class Concepts(models.IntegerChoices):
|
class Concepts(models.IntegerChoices):
|
||||||
MAKEBOND = 0, 'Maker bond'
|
MAKEBOND = 0, 'Maker bond'
|
||||||
@ -38,7 +38,7 @@ class LNPayment(models.Model):
|
|||||||
FAILRO = 7, 'Failed routing'
|
FAILRO = 7, 'Failed routing'
|
||||||
|
|
||||||
# payment use details
|
# payment use details
|
||||||
type = models.PositiveSmallIntegerField(choices=Types.choices, null=False, default=Types.HODL)
|
type = models.PositiveSmallIntegerField(choices=Types.choices, null=False, default=Types.hold)
|
||||||
concept = models.PositiveSmallIntegerField(choices=Concepts.choices, null=False, default=Concepts.MAKEBOND)
|
concept = models.PositiveSmallIntegerField(choices=Concepts.choices, null=False, default=Concepts.MAKEBOND)
|
||||||
status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.INVGEN)
|
status = models.PositiveSmallIntegerField(choices=Status.choices, null=False, default=Status.INVGEN)
|
||||||
routing_retries = models.PositiveSmallIntegerField(null=False, default=0)
|
routing_retries = models.PositiveSmallIntegerField(null=False, default=0)
|
||||||
@ -133,7 +133,7 @@ class Order(models.Model):
|
|||||||
return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency_dict[str(self.currency)]}')
|
return (f'Order {self.id}: {self.Types(self.type).label} BTC for {float(self.amount)} {self.currency_dict[str(self.currency)]}')
|
||||||
|
|
||||||
@receiver(pre_delete, sender=Order)
|
@receiver(pre_delete, sender=Order)
|
||||||
def delelete_HTLCs_at_order_deletion(sender, instance, **kwargs):
|
def delete_HTLCs_at_order_deletion(sender, instance, **kwargs):
|
||||||
to_delete = (instance.maker_bond, instance.buyer_invoice, instance.taker_bond, instance.trade_escrow)
|
to_delete = (instance.maker_bond, instance.buyer_invoice, instance.taker_bond, instance.trade_escrow)
|
||||||
|
|
||||||
for htlc in to_delete:
|
for htlc in to_delete:
|
||||||
@ -193,7 +193,7 @@ class MarketTick(models.Model):
|
|||||||
It is checked against current CEX price for useful
|
It is checked against current CEX price for useful
|
||||||
insight on the historical premium of Non-KYC BTC
|
insight on the historical premium of Non-KYC BTC
|
||||||
|
|
||||||
Price is set when both taker bond is locked. Both
|
Price is set when taker bond is locked. Both
|
||||||
maker and taker are commited with bonds (contract
|
maker and taker are commited with bonds (contract
|
||||||
is finished and cancellation has a cost)
|
is finished and cancellation has a cost)
|
||||||
'''
|
'''
|
||||||
|
15
api/views.py
15
api/views.py
@ -136,17 +136,17 @@ class OrderView(viewsets.ViewSet):
|
|||||||
elif data['is_buyer']:
|
elif data['is_buyer']:
|
||||||
data['trade_satoshis'] = Logics.buyer_invoice_amount(order, request.user)[1]['invoice_amount']
|
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.
|
# 5) If status is 'waiting for maker bond' and user is MAKER, reply with a MAKER hold invoice.
|
||||||
if order.status == Order.Status.WFB and data['is_maker']:
|
if order.status == Order.Status.WFB and data['is_maker']:
|
||||||
valid, context = Logics.gen_maker_hodl_invoice(order, request.user)
|
valid, context = Logics.gen_maker_hold_invoice(order, request.user)
|
||||||
if valid:
|
if valid:
|
||||||
data = {**data, **context}
|
data = {**data, **context}
|
||||||
else:
|
else:
|
||||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
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.
|
# 6) If status is 'waiting for taker bond' and user is TAKER, reply with a TAKER hold invoice.
|
||||||
elif order.status == Order.Status.TAK and data['is_taker']:
|
elif order.status == Order.Status.TAK and data['is_taker']:
|
||||||
valid, context = Logics.gen_taker_hodl_invoice(order, request.user)
|
valid, context = Logics.gen_taker_hold_invoice(order, request.user)
|
||||||
if valid:
|
if valid:
|
||||||
data = {**data, **context}
|
data = {**data, **context}
|
||||||
else:
|
else:
|
||||||
@ -155,9 +155,9 @@ class OrderView(viewsets.ViewSet):
|
|||||||
# 7 a. ) If seller and status is 'WF2' or 'WFE'
|
# 7 a. ) If seller and status is 'WF2' or 'WFE'
|
||||||
elif data['is_seller'] and (order.status == Order.Status.WF2 or order.status == Order.Status.WFE):
|
elif data['is_seller'] and (order.status == Order.Status.WF2 or order.status == Order.Status.WFE):
|
||||||
|
|
||||||
# If the two bonds are locked, reply with an ESCROW HODL invoice.
|
# If the two bonds are locked, reply with an ESCROW hold invoice.
|
||||||
if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED:
|
if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED:
|
||||||
valid, context = Logics.gen_escrow_hodl_invoice(order, request.user)
|
valid, context = Logics.gen_escrow_hold_invoice(order, request.user)
|
||||||
if valid:
|
if valid:
|
||||||
data = {**data, **context}
|
data = {**data, **context}
|
||||||
else:
|
else:
|
||||||
@ -180,9 +180,6 @@ class OrderView(viewsets.ViewSet):
|
|||||||
# add whether a collaborative cancel is pending
|
# add whether a collaborative cancel is pending
|
||||||
data['pending_cancel'] = order.is_pending_cancel
|
data['pending_cancel'] = order.is_pending_cancel
|
||||||
|
|
||||||
# 9) if buyer confirmed FIAT SENT
|
|
||||||
elif order.status == Order.Status.FSE:
|
|
||||||
data['buyer_confirmed']
|
|
||||||
|
|
||||||
return Response(data, status.HTTP_200_OK)
|
return Response(data, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ export default class BookPage extends Component {
|
|||||||
this.state.currencyCode = this.getCurrencyCode(this.state.currency)
|
this.state.currencyCode = this.getCurrencyCode(this.state.currency)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show message to be the first one to make an order
|
|
||||||
getOrderDetails(type,currency) {
|
getOrderDetails(type,currency) {
|
||||||
fetch('/api/book' + '?currency=' + currency + "&type=" + type)
|
fetch('/api/book' + '?currency=' + currency + "&type=" + type)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
|
@ -283,8 +283,7 @@ export default class OrderPage extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orderDetailsPage (){
|
||||||
render (){
|
|
||||||
return(
|
return(
|
||||||
this.state.badRequest ?
|
this.state.badRequest ?
|
||||||
<div align='center'>
|
<div align='center'>
|
||||||
@ -307,6 +306,13 @@ export default class OrderPage extends Component {
|
|||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
{this.orderBox()}
|
{this.orderBox()}
|
||||||
</Grid>)
|
</Grid>)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
render (){
|
||||||
|
return (
|
||||||
|
// Only so nothing shows while requesting the first batch of data
|
||||||
|
(this.state.statusCode == null & this.state.badRequest == null) ? "" : this.orderDetailsPage()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ export default class TradeBox extends Component {
|
|||||||
size="small"
|
size="small"
|
||||||
defaultValue={this.props.data.bondInvoice}
|
defaultValue={this.props.data.bondInvoice}
|
||||||
disabled="true"
|
disabled="true"
|
||||||
helperText="This is a HODL LN invoice. It will not be charged if the order succeeds or expires.
|
helperText="This is a hold invoice. It will not be charged if the order succeeds or expires.
|
||||||
It will be charged if the order is cancelled or you lose a dispute."
|
It will be charged if the order is cancelled or you lose a dispute."
|
||||||
color = "secondary"
|
color = "secondary"
|
||||||
/>
|
/>
|
||||||
@ -66,6 +66,7 @@ export default class TradeBox extends Component {
|
|||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
showEscrowQRInvoice=()=>{
|
showEscrowQRInvoice=()=>{
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
@ -84,7 +85,7 @@ export default class TradeBox extends Component {
|
|||||||
size="small"
|
size="small"
|
||||||
defaultValue={this.props.data.escrowInvoice}
|
defaultValue={this.props.data.escrowInvoice}
|
||||||
disabled="true"
|
disabled="true"
|
||||||
helperText="This is a HODL LN invoice. It will be charged once the buyer confirms he sent the fiat."
|
helperText="This is a hold LN invoice. It will be charged once the buyer confirms he sent the fiat."
|
||||||
color = "secondary"
|
color = "secondary"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -162,7 +163,7 @@ export default class TradeBox extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix this, clunky because it takes time. this.props.data does not refresh until next refresh of OrderPage.
|
// Fix this. It's clunky because it takes time. this.props.data does not refresh until next refresh of OrderPage.
|
||||||
|
|
||||||
handleClickSubmitInvoiceButton=()=>{
|
handleClickSubmitInvoiceButton=()=>{
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
@ -215,7 +216,6 @@ export default class TradeBox extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showWaitingForEscrow(){
|
showWaitingForEscrow(){
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
@ -236,7 +236,6 @@ export default class TradeBox extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showWaitingForBuyerInvoice(){
|
showWaitingForBuyerInvoice(){
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
@ -257,13 +256,24 @@ export default class TradeBox extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickFiatConfirmButton=()=>{
|
handleClickConfirmButton=()=>{
|
||||||
const requestOptions = {
|
const requestOptions = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),},
|
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
'action':'confirm',
|
'action': "confirm",
|
||||||
'invoice': this.state.invoice,
|
}),
|
||||||
|
};
|
||||||
|
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => (this.props.data = data));
|
||||||
|
}
|
||||||
|
handleClickOpenDisputeButton=()=>{
|
||||||
|
const requestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken'),},
|
||||||
|
body: JSON.stringify({
|
||||||
|
'action': "dispute",
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
|
fetch('/api/order/' + '?order_id=' + this.props.data.id, requestOptions)
|
||||||
@ -271,12 +281,65 @@ export default class TradeBox extends Component {
|
|||||||
.then((data) => (this.props.data = data));
|
.then((data) => (this.props.data = data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showFiatSentButton(){
|
showFiatSentButton(){
|
||||||
return(
|
return(
|
||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
<Button variant='contained' color='primary' onClick={this.handleClickFiatConfirmButton}>Confirm {this.props.data.currencyCode} was sent. </Button>
|
<Button defaultValue="confirm" variant='contained' color='primary' onClick={this.handleClickConfirmButton}>Confirm {this.props.data.currencyCode} sent</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
showFiatReceivedButton(){
|
||||||
|
// TODO, show alert and ask for double confirmation (Have you check you received the fiat? Confirming fiat received settles the trade.)
|
||||||
|
// Ask for double confirmation.
|
||||||
|
return(
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} align="center">
|
||||||
|
<Button defaultValue="confirm" variant='contained' color='primary' onClick={this.handleClickConfirmButton}>Confirm {this.props.data.currencyCode} received</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
showOpenDisputeButton(){
|
||||||
|
// TODO, show alert about how opening a dispute might involve giving away personal data and might mean losing the bond. Ask for double confirmation.
|
||||||
|
return(
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} align="center">
|
||||||
|
<Button defaultValue="dispute" variant='contained' onClick={this.handleClickOpenDisputeButton}>Open Dispute</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
showChat(sendFiatButton, receivedFiatButton, openDisputeButton){
|
||||||
|
return(
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} align="center">
|
||||||
|
<Typography component="subtitle1" variant="subtitle1">
|
||||||
|
<b>Chatting with {this.props.data.isMaker ? this.props.data.takerNick : this.props.data.makerNick}</b>
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} align="left">
|
||||||
|
{this.props.data.isSeller ?
|
||||||
|
<Typography component="body2" variant="body2">
|
||||||
|
Say hi to your peer robot! Be helpful and concise. Let him know how to send you {this.props.data.currencyCode}.
|
||||||
|
</Typography>
|
||||||
|
:
|
||||||
|
<Typography component="body2" variant="body2">
|
||||||
|
Say hi to your peer robot! Ask for payment details and click 'Confirm {this.props.data.currencyCode} sent' as soon as you send the payment.
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} style={{ width:330, height:360}}>
|
||||||
|
CHAT PLACEHOLDER
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} align="center">
|
||||||
|
{sendFiatButton ? this.showFiatSentButton() : ""}
|
||||||
|
{receivedFiatButton ? this.showFiatReceivedButton() : ""}
|
||||||
|
{openDisputeButton ? this.showOpenDisputeButton() : ""}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
)
|
)
|
||||||
@ -316,11 +379,11 @@ export default class TradeBox extends Component {
|
|||||||
{this.props.data.isBuyer & this.props.data.statusCode == 7 ? this.showWaitingForEscrow() : ""}
|
{this.props.data.isBuyer & this.props.data.statusCode == 7 ? this.showWaitingForEscrow() : ""}
|
||||||
{this.props.data.isSeller & this.props.data.statusCode == 8 ? this.showWaitingForBuyerInvoice() : ""}
|
{this.props.data.isSeller & this.props.data.statusCode == 8 ? this.showWaitingForBuyerInvoice() : ""}
|
||||||
|
|
||||||
{/* In Chatroom */}
|
{/* In Chatroom - showChat(showSendButton, showReveiceButton, showDisputeButton) */}
|
||||||
{this.props.data.isBuyer & this.props.data.statusCode == 9 ? this.showChat() & this.showFiatSentButton() : ""}
|
{this.props.data.isBuyer & this.props.data.statusCode == 9 ? this.showChat(true,false,true) : ""}
|
||||||
{this.props.data.isSeller & this.props.data.statusCode ==9 ? this.showChat() : ""}
|
{this.props.data.isSeller & this.props.data.statusCode == 9 ? this.showChat(false,false,true) : ""}
|
||||||
{this.props.data.isBuyer & this.props.data.statusCode == 10 ? this.showChat() & this.showOpenDisputeButton() : ""}
|
{this.props.data.isBuyer & this.props.data.statusCode == 10 ? this.showChat(false,false,true) : ""}
|
||||||
{this.props.data.isSeller & this.props.data.statusCode == 10 ? this.showChat() & this.showFiatReceivedButton() & this.showOpenDisputeButton(): ""}
|
{this.props.data.isSeller & this.props.data.statusCode == 10 ? this.showChat(false,true,true) : ""}
|
||||||
|
|
||||||
{/* Trade Finished */}
|
{/* Trade Finished */}
|
||||||
{this.props.data.isSeller & this.props.data.statusCode > 12 & this.props.data.statusCode < 15 ? this.showRateSelect() : ""}
|
{this.props.data.isSeller & this.props.data.statusCode > 12 & this.props.data.statusCode < 15 ? this.showRateSelect() : ""}
|
||||||
|
Loading…
Reference in New Issue
Block a user