mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Add cancel taker penalty time
This commit is contained in:
parent
cf11583d6d
commit
de66040893
@ -5,6 +5,8 @@ MARKET_PRICE_API = 'https://blockchain.info/ticker'
|
||||
FEE = 0.002
|
||||
# Bond size in percentage %
|
||||
BOND_SIZE = 0.01
|
||||
# Time out penalty for canceling takers in MINUTES
|
||||
PENALTY_TIMEOUT = 2
|
||||
|
||||
# Trade limits in satoshis
|
||||
MIN_TRADE = 10000
|
||||
|
@ -10,6 +10,7 @@ FEE = float(config('FEE'))
|
||||
BOND_SIZE = float(config('BOND_SIZE'))
|
||||
MARKET_PRICE_API = config('MARKET_PRICE_API')
|
||||
ESCROW_USERNAME = config('ESCROW_USERNAME')
|
||||
PENALTY_TIMEOUT = int(config('PENALTY_TIMEOUT'))
|
||||
|
||||
MIN_TRADE = int(config('MIN_TRADE'))
|
||||
MAX_TRADE = int(config('MAX_TRADE'))
|
||||
@ -21,6 +22,7 @@ EXP_TRADE_ESCR_INVOICE = int(config('EXP_TRADE_ESCR_INVOICE'))
|
||||
BOND_EXPIRY = int(config('BOND_EXPIRY'))
|
||||
ESCROW_EXPIRY = int(config('ESCROW_EXPIRY'))
|
||||
|
||||
|
||||
class Logics():
|
||||
|
||||
def validate_already_maker_or_taker(user):
|
||||
@ -41,10 +43,16 @@ class Logics():
|
||||
return False, {'bad_request': 'Your order is too small. It is worth '+'{:,}'.format(order.t0_satoshis)+' Sats now. But limit is '+'{:,}'.format(MIN_TRADE)+ ' Sats'}
|
||||
return True, None
|
||||
|
||||
def take(order, user):
|
||||
@classmethod
|
||||
def take(cls, order, user):
|
||||
is_penalized, time_out = cls.is_penalized(user)
|
||||
if is_penalized:
|
||||
return False, {'bad_request',f'You need to wait {time_out} seconds to take an order'}
|
||||
else:
|
||||
order.taker = user
|
||||
order.status = Order.Status.TAK
|
||||
order.save()
|
||||
return True, None
|
||||
|
||||
def is_buyer(order, user):
|
||||
is_maker = order.maker == user
|
||||
@ -167,6 +175,18 @@ class Logics():
|
||||
order.save()
|
||||
return True, None
|
||||
|
||||
def is_penalized(user):
|
||||
''' Checks if a user that is not participant of orders
|
||||
has a limit on taking or making a order'''
|
||||
|
||||
if user.profile.penalty_expiration:
|
||||
if user.profile.penalty_expiration > timezone.now():
|
||||
time_out = (user.profile.penalty_expiration - timezone.now()).seconds
|
||||
return True, time_out
|
||||
|
||||
return False, None
|
||||
|
||||
|
||||
@classmethod
|
||||
def cancel_order(cls, order, user, state=None):
|
||||
|
||||
@ -181,12 +201,24 @@ class Logics():
|
||||
|
||||
# 2) When maker cancels after bond
|
||||
'''The order dissapears from book and goes to cancelled.
|
||||
Maker is charged a small amount of sats, to prevent DDOS
|
||||
on the LN node and order book'''
|
||||
Maker is charged the bond to prevent DDOS
|
||||
on the LN node and order book. TODO Only charge a small part
|
||||
of the bond (requires maker submitting an invoice)'''
|
||||
|
||||
|
||||
# 3) When taker cancels before bond
|
||||
''' The order goes back to the book as public.
|
||||
LNPayment "order.taker_bond" is deleted() '''
|
||||
elif order.status == Order.Status.TAK and order.taker == user:
|
||||
# adds a timeout penalty
|
||||
user.profile.penalty_expiration = timezone.now() + timedelta(seconds=PENALTY_TIMEOUT)
|
||||
user.save()
|
||||
|
||||
order.taker = None
|
||||
order.status = Order.Status.PUB
|
||||
order.save()
|
||||
|
||||
return True, None
|
||||
|
||||
# 4) When taker or maker cancel after bond (before escrow)
|
||||
'''The order goes into cancelled status if maker cancels.
|
||||
|
@ -158,6 +158,9 @@ class Profile(models.Model):
|
||||
# RoboHash
|
||||
avatar = models.ImageField(default="static/assets/misc/unknown_avatar.png", verbose_name='Avatar', blank=True)
|
||||
|
||||
# Penalty expiration (only used then taking/cancelling repeatedly orders in the book before comitting bond)
|
||||
penalty_expiration = models.DateTimeField(null=True)
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
|
@ -5,7 +5,7 @@ import ring
|
||||
|
||||
storage = {}
|
||||
|
||||
@ring.dict(storage, expire=10) #keeps in cache for 10 seconds
|
||||
@ring.dict(storage, expire=30) #keeps in cache for 30 seconds
|
||||
def get_exchange_rate(currency):
|
||||
# TODO Add fallback Public APIs and error handling
|
||||
# Think about polling price data in a different way (e.g. store locally every t seconds)
|
||||
|
@ -105,6 +105,11 @@ class OrderView(viewsets.ViewSet):
|
||||
|
||||
data = ListOrderSerializer(order).data
|
||||
|
||||
# if user is under a limit (penalty), inform him
|
||||
is_penalized, time_out = Logics.is_penalized(request.user)
|
||||
if is_penalized:
|
||||
data['penalty'] = time_out
|
||||
|
||||
# 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
|
||||
@ -207,7 +212,9 @@ class OrderView(viewsets.ViewSet):
|
||||
valid, context = Logics.validate_already_maker_or_taker(request.user)
|
||||
if not valid: return Response(context, status=status.HTTP_409_CONFLICT)
|
||||
|
||||
Logics.take(order, request.user)
|
||||
valid, context = Logics.take(order, request.user)
|
||||
if not valid: return Response(context, status=status.HTTP_403_FORBIDDEN)
|
||||
|
||||
else: Response({'bad_request':'This order is not public anymore.'}, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Any other action is only allowed if the user is a participant
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { Component } from "react";
|
||||
import { Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material"
|
||||
import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material"
|
||||
import TradeBox from "./TradeBox";
|
||||
|
||||
function msToTime(duration) {
|
||||
@ -101,6 +101,7 @@ export default class OrderPage extends Component {
|
||||
isTaker: data.is_taker,
|
||||
isBuyer: data.is_buyer,
|
||||
isSeller: data.is_seller,
|
||||
penalty: data.penalty,
|
||||
expiresAt: data.expires_at,
|
||||
badRequest: data.bad_request,
|
||||
bondInvoice: data.bond_invoice,
|
||||
@ -250,6 +251,18 @@ export default class OrderPage extends Component {
|
||||
<LinearDeterminate />
|
||||
</List>
|
||||
|
||||
{/* If the user has a penalty/limit */}
|
||||
{this.state.penalty ?
|
||||
<>
|
||||
<Divider />
|
||||
<Grid item xs={12} align="center">
|
||||
<Alert severity="warning" sx={{maxWidth:360}}>
|
||||
You cannot take an order yet! Wait {this.state.penalty} seconds
|
||||
</Alert>
|
||||
</Grid>
|
||||
</>
|
||||
: null}
|
||||
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user