mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-18 12:11:35 +00:00
Improve logics around locked bonds. Add frontend confirm cancel dialog.
This commit is contained in:
parent
e31bc1adad
commit
c58070f437
@ -125,7 +125,7 @@ class Logics():
|
||||
elif order.status == Order.Status.WFB:
|
||||
order.status = Order.Status.EXP
|
||||
cls.cancel_bond(order.maker_bond)
|
||||
order.maker = None
|
||||
order.maker = None # TODO with the new validate_already_maker_taker there is no need to kick out participants on expired orders.
|
||||
order.taker = None
|
||||
order.save()
|
||||
return True
|
||||
@ -175,12 +175,10 @@ class Logics():
|
||||
else:
|
||||
cls.settle_bond(order.taker_bond)
|
||||
cls.cancel_escrow(order)
|
||||
order.status = Order.Status.PUB
|
||||
order.taker = None
|
||||
order.taker_bond = None
|
||||
order.trade_escrow = None
|
||||
order.expires_at = order.created_at + timedelta(seconds=Order.t_to_expire[Order.Status.PUB])
|
||||
order.save()
|
||||
cls.publish_order(order)
|
||||
return True
|
||||
|
||||
elif order.status == Order.Status.WFI:
|
||||
@ -203,12 +201,10 @@ class Logics():
|
||||
else:
|
||||
cls.settle_bond(order.taker_bond)
|
||||
cls.return_escrow(order)
|
||||
order.status = Order.Status.PUB
|
||||
order.taker = None
|
||||
order.taker_bond = None
|
||||
order.trade_escrow = None
|
||||
order.expires_at = order.created_at + timedelta(seconds=Order.t_to_expire[Order.Status.PUB])
|
||||
order.save()
|
||||
cls.publish_order(order)
|
||||
return True
|
||||
|
||||
elif order.status == Order.Status.CHA:
|
||||
@ -218,7 +214,8 @@ class Logics():
|
||||
cls.open_dispute(order)
|
||||
return True
|
||||
|
||||
def kick_taker(order):
|
||||
@classmethod
|
||||
def kick_taker(cls, order):
|
||||
''' The taker did not lock the taker_bond. Now he has to go'''
|
||||
# Add a time out to the taker
|
||||
profile = order.taker.profile
|
||||
@ -226,11 +223,9 @@ class Logics():
|
||||
profile.save()
|
||||
|
||||
# Make order public again
|
||||
order.status = Order.Status.PUB
|
||||
order.taker = None
|
||||
order.taker_bond = None
|
||||
order.expires_at = order.created_at + timedelta(seconds=Order.t_to_expire[Order.Status.PUB])
|
||||
order.save()
|
||||
cls.publish_order(order)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
@ -417,14 +412,12 @@ class Logics():
|
||||
|
||||
# 4.b) When taker cancel after bond (before escrow)
|
||||
'''The order into cancelled status if maker cancels.'''
|
||||
elif order.status > Order.Status.TAK and order.status < Order.Status.CHA and order.taker == user:
|
||||
elif order.status in [Order.Status.WF2, Order.Status.WFE] and order.taker == user:
|
||||
# Settle the maker bond (Maker loses the bond for canceling an ongoing trade)
|
||||
valid = cls.settle_bond(order.taker_bond)
|
||||
if valid:
|
||||
order.taker = None
|
||||
order.status = Order.Status.PUB
|
||||
# order.taker_bond = None # TODO fix this, it overrides the information about the settled taker bond. Might make admin tasks hard.
|
||||
order.save()
|
||||
cls.publish_order(order)
|
||||
return True, None
|
||||
|
||||
# 5) When trade collateral has been posted (after escrow)
|
||||
@ -437,12 +430,10 @@ class Logics():
|
||||
return False, {'bad_request':'You cannot cancel this order'}
|
||||
|
||||
def publish_order(order):
|
||||
if order.status == Order.Status.WFB:
|
||||
order.status = Order.Status.PUB
|
||||
# With the bond confirmation the order is extended 'public_order_duration' hours
|
||||
order.expires_at = order.created_at + timedelta(seconds=Order.t_to_expire[Order.Status.PUB])
|
||||
order.save()
|
||||
return
|
||||
order.status = Order.Status.PUB
|
||||
order.expires_at = order.created_at + timedelta(seconds=Order.t_to_expire[Order.Status.PUB])
|
||||
order.save()
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def is_maker_bond_locked(cls, order):
|
||||
|
16
api/views.py
16
api/views.py
@ -166,14 +166,14 @@ class OrderView(viewsets.ViewSet):
|
||||
data['escrow_locked'] = False
|
||||
|
||||
# If both bonds are locked, participants can see the final trade amount in sats.
|
||||
if order.taker_bond:
|
||||
if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED:
|
||||
# Seller sees the amount he sends
|
||||
if data['is_seller']:
|
||||
data['trade_satoshis'] = order.last_satoshis
|
||||
# Buyer sees the amount he receives
|
||||
elif data['is_buyer']:
|
||||
data['trade_satoshis'] = Logics.buyer_invoice_amount(order, request.user)[1]['invoice_amount']
|
||||
# if order.taker_bond:
|
||||
# if order.maker_bond.status == order.taker_bond.status == LNPayment.Status.LOCKED:
|
||||
# # Seller sees the amount he sends
|
||||
# if data['is_seller']:
|
||||
# data['trade_satoshis'] = order.last_satoshis
|
||||
# # Buyer sees the amount he receives
|
||||
# elif data['is_buyer']:
|
||||
# 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 hold invoice.
|
||||
if order.status == Order.Status.WFB and data['is_maker']:
|
||||
|
@ -166,10 +166,10 @@ export default class BookPage extends Component {
|
||||
style: {textAlign:"center"}
|
||||
}}
|
||||
onChange={this.handleCurrencyChange}
|
||||
> <MenuItem value={0}>ANY</MenuItem>
|
||||
> <MenuItem value={0}>🌍 ANY</MenuItem>
|
||||
{
|
||||
Object.entries(this.state.currencies_dict)
|
||||
.map( ([key, value]) => <MenuItem value={parseInt(key)}>{value}</MenuItem> )
|
||||
.map( ([key, value]) => <MenuItem value={parseInt(key)}>{getFlags(value) + " " + value}</MenuItem> )
|
||||
}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { Component } from "react";
|
||||
import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress} from "@mui/material"
|
||||
import { Alert, Paper, CircularProgress, Button , Grid, Typography, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, Avatar, Divider, Box, LinearProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle} from "@mui/material"
|
||||
import Countdown, { zeroPad, calcTimeDelta } from 'react-countdown';
|
||||
import TradeBox from "./TradeBox";
|
||||
import getFlags from './getFlags'
|
||||
@ -11,6 +11,7 @@ import PriceChangeIcon from '@mui/icons-material/PriceChange';
|
||||
import PaymentsIcon from '@mui/icons-material/Payments';
|
||||
import MoneyIcon from '@mui/icons-material/Money';
|
||||
import ArticleIcon from '@mui/icons-material/Article';
|
||||
import ContentCopy from "@mui/icons-material/ContentCopy";
|
||||
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
@ -43,6 +44,7 @@ export default class OrderPage extends Component {
|
||||
currencies_dict: {"1":"USD"},
|
||||
total_secs_expiry: 300,
|
||||
loading: true,
|
||||
openCancel: false,
|
||||
};
|
||||
this.orderId = this.props.match.params.orderId;
|
||||
this.getCurrencyDict();
|
||||
@ -144,8 +146,8 @@ export default class OrderPage extends Component {
|
||||
countdownRenderer = ({ total, hours, minutes, seconds, completed }) => {
|
||||
if (completed) {
|
||||
// Render a completed state
|
||||
this.getOrderDetails();
|
||||
return null;
|
||||
return (<span> The order has expired</span>);
|
||||
|
||||
} else {
|
||||
var col = 'black'
|
||||
var fraction_left = (total/1000) / this.state.total_secs_expiry
|
||||
@ -218,7 +220,7 @@ export default class OrderPage extends Component {
|
||||
return code
|
||||
}
|
||||
|
||||
handleClickCancelOrderButton=()=>{
|
||||
handleClickConfirmCancelButton=()=>{
|
||||
console.log(this.state)
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
@ -230,6 +232,64 @@ export default class OrderPage extends Component {
|
||||
fetch('/api/order/' + '?order_id=' + this.orderId, requestOptions)
|
||||
.then((response) => response.json())
|
||||
.then((data) => (console.log(data) & this.getOrderDetails(data.id)));
|
||||
this.handleClickCloseConfirmCancelDialog();
|
||||
}
|
||||
|
||||
handleClickOpenConfirmCancelDialog = () => {
|
||||
this.setState({openCancel: true});
|
||||
};
|
||||
handleClickCloseConfirmCancelDialog = () => {
|
||||
this.setState({openCancel: false});
|
||||
};
|
||||
|
||||
CancelDialog =() =>{
|
||||
return(
|
||||
<Dialog
|
||||
open={this.state.openCancel}
|
||||
onClose={this.handleClickCloseConfirmCancelDialog}
|
||||
aria-labelledby="cancel-dialog-title"
|
||||
aria-describedby="cancel-dialog-description"
|
||||
>
|
||||
<DialogTitle id="cancel-dialog-title">
|
||||
{"Cancel the order?"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="cancel-dialog-description">
|
||||
If the order is cancelled now you will lose your bond.
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClickCloseConfirmCancelDialog} autoFocus>Go back</Button>
|
||||
<Button onClick={this.handleClickConfirmCancelButton}> Confirm Cancel </Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
CancelButton = () => {
|
||||
|
||||
// If maker and Waiting for Bond. Or if taker and Waiting for bond.
|
||||
// Simply allow to cancel without showing the cancel dialog.
|
||||
if ((this.state.isMaker & this.state.statusCode == 0) || this.state.isTaker & this.state.statusCode == 3){
|
||||
return(
|
||||
<Grid item xs={12} align="center">
|
||||
<Button variant='contained' color='secondary' onClick={this.handleClickConfirmCancelButton}>Cancel</Button>
|
||||
</Grid>
|
||||
)}
|
||||
// If the order does not yet have an escrow deposited. Show dialog
|
||||
// to confirm forfeiting the bond
|
||||
if (this.state.statusCode < 8){
|
||||
return(
|
||||
<Grid item xs={12} align="center">
|
||||
<this.CancelDialog/>
|
||||
<Button variant='contained' color='secondary' onClick={this.handleClickOpenConfirmCancelDialog}>Cancel</Button>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
// TODO If the escrow is Locked, show the collaborative cancel button.
|
||||
|
||||
// If none of the above do not return a cancel button.
|
||||
return(null)
|
||||
}
|
||||
|
||||
orderBox=()=>{
|
||||
@ -346,8 +406,10 @@ export default class OrderPage extends Component {
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
||||
{/* Participants cannot see the Back or Take Order buttons */}
|
||||
{this.state.isParticipant ? "" :
|
||||
{/* Participants can see the "Cancel" Button, but cannot see the "Back" or "Take Order" buttons */}
|
||||
{this.state.isParticipant ?
|
||||
<this.CancelButton/>
|
||||
:
|
||||
<>
|
||||
<Grid item xs={12} align="center">
|
||||
<Button variant='contained' color='primary' onClick={this.handleClickTakeOrderButton}>Take Order</Button>
|
||||
@ -358,27 +420,7 @@ export default class OrderPage extends Component {
|
||||
</>
|
||||
}
|
||||
|
||||
{/* Makers can cancel before trade escrow deposited (status <9)*/}
|
||||
{/* Only free cancel before bond locked (status 0)*/}
|
||||
{this.state.isMaker & this.state.statusCode < 9 ?
|
||||
<Grid item xs={12} align="center">
|
||||
<Button variant='contained' color='secondary' onClick={this.handleClickCancelOrderButton}>Cancel</Button>
|
||||
</Grid>
|
||||
:""}
|
||||
{this.state.isMaker & this.state.statusCode > 0 & this.state.statusCode < 9 ?
|
||||
<Grid item xs={12} align="center">
|
||||
<Typography color="secondary" variant="subtitle2" component="subtitle2">Cancelling now forfeits the maker bond</Typography>
|
||||
</Grid>
|
||||
:""}
|
||||
|
||||
{/* Takers can cancel before commiting the bond (status 3)*/}
|
||||
{this.state.isTaker & this.state.statusCode == 3 ?
|
||||
<Grid item xs={12} align="center">
|
||||
<Button variant='contained' color='secondary' onClick={this.handleClickCancelOrderButton}>Cancel</Button>
|
||||
</Grid>
|
||||
:""}
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ export default class TradeBox extends Component {
|
||||
return (
|
||||
<Grid container spacing={1}>
|
||||
<Grid item xs={12} align="center">
|
||||
<Typography color="primary" component="subtitle1" variant="subtitle1">
|
||||
<Typography color="green" component="subtitle1" variant="subtitle1">
|
||||
<b>Deposit {pn(this.props.data.escrowSatoshis)} Sats as trade collateral </b>
|
||||
</Typography>
|
||||
</Grid>
|
||||
@ -569,7 +569,6 @@ handleRatingChange=(e)=>{
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Grid container spacing={1} style={{ width:330}}>
|
||||
|
@ -150,15 +150,15 @@ export default class UserGenPage extends Component {
|
||||
<Grid container align="center">
|
||||
<Grid item xs={12} align="center">
|
||||
<IconButton onClick= {()=>navigator.clipboard.writeText(this.state.token)}>
|
||||
<ContentCopy color='secondary'/>
|
||||
<ContentCopy/>
|
||||
</IconButton>
|
||||
<TextField
|
||||
//sx={{ input: { color: 'purple' } }}
|
||||
InputLabelProps={{
|
||||
style: { color: 'purple' },
|
||||
style: { color: 'green' },
|
||||
}}
|
||||
error={this.state.bad_request}
|
||||
label='Token - Store safely'
|
||||
label='Store your token safely'
|
||||
required='true'
|
||||
value={this.state.token}
|
||||
variant='standard'
|
||||
|
Loading…
Reference in New Issue
Block a user