mirror of
https://github.com/RoboSats/robosats.git
synced 2025-07-20 01:33:15 +00:00
Add maker selects fidelity bond size
This commit is contained in:
@ -55,8 +55,10 @@ FEE = 0.002
|
|||||||
# Shall incentivize order making
|
# Shall incentivize order making
|
||||||
MAKER_FEE_SPLIT=0.125
|
MAKER_FEE_SPLIT=0.125
|
||||||
|
|
||||||
# Default bond size as fraction
|
# Bond size as percentage (%)
|
||||||
BOND_SIZE = 0.01
|
DEFAULT_BOND_SIZE = 1
|
||||||
|
MIN_BOND_SIZE = 1
|
||||||
|
MAX_BOND_SIZE = 15
|
||||||
|
|
||||||
# Time out penalty for canceling takers in SECONDS
|
# Time out penalty for canceling takers in SECONDS
|
||||||
PENALTY_TIMEOUT = 60
|
PENALTY_TIMEOUT = 60
|
||||||
|
@ -14,7 +14,6 @@ import time
|
|||||||
FEE = float(config("FEE"))
|
FEE = float(config("FEE"))
|
||||||
MAKER_FEE_SPLIT = float(config("MAKER_FEE_SPLIT"))
|
MAKER_FEE_SPLIT = float(config("MAKER_FEE_SPLIT"))
|
||||||
|
|
||||||
BOND_SIZE = float(config("BOND_SIZE"))
|
|
||||||
ESCROW_USERNAME = config("ESCROW_USERNAME")
|
ESCROW_USERNAME = config("ESCROW_USERNAME")
|
||||||
PENALTY_TIMEOUT = int(config("PENALTY_TIMEOUT"))
|
PENALTY_TIMEOUT = int(config("PENALTY_TIMEOUT"))
|
||||||
|
|
||||||
@ -698,7 +697,7 @@ class Logics:
|
|||||||
|
|
||||||
# If there was no maker_bond object yet, generates one
|
# If there was no maker_bond object yet, generates one
|
||||||
order.last_satoshis = cls.satoshis_now(order)
|
order.last_satoshis = cls.satoshis_now(order)
|
||||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
|
||||||
|
|
||||||
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
|
||||||
|
|
||||||
@ -808,7 +807,7 @@ class Logics:
|
|||||||
|
|
||||||
# If there was no taker_bond object yet, generates one
|
# If there was no taker_bond object yet, generates one
|
||||||
order.last_satoshis = cls.satoshis_now(order)
|
order.last_satoshis = cls.satoshis_now(order)
|
||||||
bond_satoshis = int(order.last_satoshis * BOND_SIZE)
|
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
|
||||||
pos_text = "Buying" if cls.is_buyer(order, user) else "Selling"
|
pos_text = "Buying" if cls.is_buyer(order, user) else "Selling"
|
||||||
description = (
|
description = (
|
||||||
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
|
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
|
||||||
|
@ -20,7 +20,7 @@ import json
|
|||||||
MIN_TRADE = int(config("MIN_TRADE"))
|
MIN_TRADE = int(config("MIN_TRADE"))
|
||||||
MAX_TRADE = int(config("MAX_TRADE"))
|
MAX_TRADE = int(config("MAX_TRADE"))
|
||||||
FEE = float(config("FEE"))
|
FEE = float(config("FEE"))
|
||||||
BOND_SIZE = float(config("BOND_SIZE"))
|
DEFAULT_BOND_SIZE = float(config("DEFAULT_BOND_SIZE"))
|
||||||
|
|
||||||
|
|
||||||
class Currency(models.Model):
|
class Currency(models.Model):
|
||||||
@ -106,8 +106,8 @@ class LNPayment(models.Model):
|
|||||||
default=None,
|
default=None,
|
||||||
blank=True)
|
blank=True)
|
||||||
num_satoshis = models.PositiveBigIntegerField(validators=[
|
num_satoshis = models.PositiveBigIntegerField(validators=[
|
||||||
MinValueValidator(MIN_TRADE * BOND_SIZE),
|
MinValueValidator(100),
|
||||||
MaxValueValidator(MAX_TRADE * (1 + BOND_SIZE + FEE)),
|
MaxValueValidator(MAX_TRADE * (1 + DEFAULT_BOND_SIZE + FEE)),
|
||||||
])
|
])
|
||||||
created_at = models.DateTimeField()
|
created_at = models.DateTimeField()
|
||||||
expires_at = models.DateTimeField()
|
expires_at = models.DateTimeField()
|
||||||
@ -229,6 +229,18 @@ class Order(models.Model):
|
|||||||
],
|
],
|
||||||
blank=False,
|
blank=False,
|
||||||
)
|
)
|
||||||
|
# optionally makers can choose the fidelity bond size of the maker and taker (%)
|
||||||
|
bond_size = models.DecimalField(
|
||||||
|
max_digits=4,
|
||||||
|
decimal_places=2,
|
||||||
|
default=DEFAULT_BOND_SIZE,
|
||||||
|
null=False,
|
||||||
|
validators=[
|
||||||
|
MinValueValidator(float(config("MIN_BOND_SIZE"))), # 1 %
|
||||||
|
MaxValueValidator(float(config("MAX_BOND_SIZE"))), # 15 %
|
||||||
|
],
|
||||||
|
blank=False,
|
||||||
|
)
|
||||||
|
|
||||||
# how many sats at creation and at last check (relevant for marked to market)
|
# how many sats at creation and at last check (relevant for marked to market)
|
||||||
t0_satoshis = models.PositiveBigIntegerField(
|
t0_satoshis = models.PositiveBigIntegerField(
|
||||||
|
@ -36,6 +36,7 @@ class MakeOrderSerializer(serializers.ModelSerializer):
|
|||||||
"premium",
|
"premium",
|
||||||
"satoshis",
|
"satoshis",
|
||||||
"public_duration",
|
"public_duration",
|
||||||
|
"bond_size",
|
||||||
)
|
)
|
||||||
|
|
||||||
class UpdateOrderSerializer(serializers.Serializer):
|
class UpdateOrderSerializer(serializers.Serializer):
|
||||||
|
14
api/views.py
14
api/views.py
@ -30,6 +30,8 @@ from decouple import config
|
|||||||
|
|
||||||
EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE"))
|
EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE"))
|
||||||
RETRY_TIME = int(config("RETRY_TIME"))
|
RETRY_TIME = int(config("RETRY_TIME"))
|
||||||
|
PUBLIC_DURATION = 60*60*int(config("DEFAULT_PUBLIC_ORDER_DURATION"))-1
|
||||||
|
BOND_SIZE = int(config("DEFAULT_BOND_SIZE"))
|
||||||
|
|
||||||
avatar_path = Path(settings.AVATAR_ROOT)
|
avatar_path = Path(settings.AVATAR_ROOT)
|
||||||
avatar_path.mkdir(parents=True, exist_ok=True)
|
avatar_path.mkdir(parents=True, exist_ok=True)
|
||||||
@ -73,6 +75,13 @@ class MakerView(CreateAPIView):
|
|||||||
satoshis = serializer.data.get("satoshis")
|
satoshis = serializer.data.get("satoshis")
|
||||||
is_explicit = serializer.data.get("is_explicit")
|
is_explicit = serializer.data.get("is_explicit")
|
||||||
public_duration = serializer.data.get("public_duration")
|
public_duration = serializer.data.get("public_duration")
|
||||||
|
bond_size = serializer.data.get("bond_size")
|
||||||
|
|
||||||
|
# Optional params
|
||||||
|
if public_duration == None:
|
||||||
|
public_duration = PUBLIC_DURATION
|
||||||
|
if bond_size == None:
|
||||||
|
bond_size = BOND_SIZE
|
||||||
|
|
||||||
valid, context, _ = Logics.validate_already_maker_or_taker(
|
valid, context, _ = Logics.validate_already_maker_or_taker(
|
||||||
request.user)
|
request.user)
|
||||||
@ -89,9 +98,10 @@ class MakerView(CreateAPIView):
|
|||||||
satoshis=satoshis,
|
satoshis=satoshis,
|
||||||
is_explicit=is_explicit,
|
is_explicit=is_explicit,
|
||||||
expires_at=timezone.now() + timedelta(
|
expires_at=timezone.now() + timedelta(
|
||||||
seconds=EXP_MAKER_BOND_INVOICE), # TODO Move to class method
|
seconds=EXP_MAKER_BOND_INVOICE),
|
||||||
maker=request.user,
|
maker=request.user,
|
||||||
public_duration=public_duration,
|
public_duration=public_duration,
|
||||||
|
bond_size=bond_size,
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO move to Order class method when new instance is created!
|
# TODO move to Order class method when new instance is created!
|
||||||
@ -686,7 +696,7 @@ class InfoView(ListAPIView):
|
|||||||
context["network"] = config("NETWORK")
|
context["network"] = config("NETWORK")
|
||||||
context["maker_fee"] = float(config("FEE"))*float(config("MAKER_FEE_SPLIT"))
|
context["maker_fee"] = float(config("FEE"))*float(config("MAKER_FEE_SPLIT"))
|
||||||
context["taker_fee"] = float(config("FEE"))*(1 - float(config("MAKER_FEE_SPLIT")))
|
context["taker_fee"] = float(config("FEE"))*(1 - float(config("MAKER_FEE_SPLIT")))
|
||||||
context["bond_size"] = float(config("BOND_SIZE"))
|
context["bond_size"] = float(config("DEFAULT_BOND_SIZE"))
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
context["nickname"] = request.user.username
|
context["nickname"] = request.user.username
|
||||||
|
@ -59,7 +59,6 @@ export default class MakerPage extends Component {
|
|||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
allowBondless: false,
|
allowBondless: false,
|
||||||
publicExpiryTime: new Date(0, 0, 0, 23, 59),
|
publicExpiryTime: new Date(0, 0, 0, 23, 59),
|
||||||
publicDuration: 23*60*60 + 59*60,
|
|
||||||
enableAmountRange: false,
|
enableAmountRange: false,
|
||||||
minAmount: null,
|
minAmount: null,
|
||||||
bondSize: 1,
|
bondSize: 1,
|
||||||
@ -139,7 +138,6 @@ export default class MakerPage extends Component {
|
|||||||
|
|
||||||
handleCreateOfferButtonPressed=()=>{
|
handleCreateOfferButtonPressed=()=>{
|
||||||
this.state.amount == null ? this.setState({amount: 0}) : null;
|
this.state.amount == null ? this.setState({amount: 0}) : null;
|
||||||
|
|
||||||
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')},
|
||||||
@ -152,6 +150,7 @@ export default class MakerPage extends Component {
|
|||||||
premium: this.state.is_explicit ? null: this.state.premium,
|
premium: this.state.is_explicit ? null: this.state.premium,
|
||||||
satoshis: this.state.is_explicit ? this.state.satoshis: null,
|
satoshis: this.state.is_explicit ? this.state.satoshis: null,
|
||||||
public_duration: this.state.publicDuration,
|
public_duration: this.state.publicDuration,
|
||||||
|
bond_size: this.state.bondSize,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
fetch("/api/make/",requestOptions)
|
fetch("/api/make/",requestOptions)
|
||||||
@ -174,19 +173,6 @@ export default class MakerPage extends Component {
|
|||||||
return this.state.currencies_dict[val.toString()]
|
return this.state.currencies_dict[val.toString()]
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBlur = () => {
|
|
||||||
if (this.state.bondSize < 0) {
|
|
||||||
this.setState({bondSize:0});
|
|
||||||
} else if (this.state.bondSize > 100) {
|
|
||||||
this.setState({bondSize:20});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
handleSliderBondSizeChange = (event, newValue) => {
|
|
||||||
this.setState({bondSize: newValue});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleInputBondSizeChange = (event) => {
|
handleInputBondSizeChange = (event) => {
|
||||||
this.setState({bondSize: event.target.value === '' ? 1 : Number(event.target.value)});
|
this.setState({bondSize: event.target.value === '' ? 1 : Number(event.target.value)});
|
||||||
};
|
};
|
||||||
@ -358,9 +344,36 @@ export default class MakerPage extends Component {
|
|||||||
AdvancedMakerOptions = () => {
|
AdvancedMakerOptions = () => {
|
||||||
return(
|
return(
|
||||||
<Paper elevation={12} style={{ padding: 8, width:280, align:'center'}}>
|
<Paper elevation={12} style={{ padding: 8, width:280, align:'center'}}>
|
||||||
|
|
||||||
<Grid container xs={12} spacing={1}>
|
<Grid container xs={12} spacing={1}>
|
||||||
|
|
||||||
|
<Grid item xs={12} align="center" spacing={1}>
|
||||||
|
<FormControl align="center">
|
||||||
|
<FormHelperText>
|
||||||
|
<Tooltip enterTouchDelay="0" title={"Set the skin-in-the-game (increase for higher safety assurance)"}>
|
||||||
|
<div align="center" style={{display:'flex',flexWrap:'wrap', transform: 'translate(20%, 0)'}}>
|
||||||
|
Fidelity Bond Size <LockIcon sx={{height:20,width:20}}/>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</FormHelperText>
|
||||||
|
|
||||||
|
<Slider
|
||||||
|
sx={{width:220, align:"center"}}
|
||||||
|
aria-label="Bond Size (%)"
|
||||||
|
defaultValue={1}
|
||||||
|
valueLabelDisplay="auto"
|
||||||
|
valueLabelFormat={(x) => (x+'%')}
|
||||||
|
step={0.25}
|
||||||
|
marks={[{value: 1,label: '1%'},{value: 5,label: '5%'},{value: 10,label: '10%'},{value: 15,label: '15%'}]}
|
||||||
|
min={1}
|
||||||
|
max={15}
|
||||||
|
onChange={(e) => this.setState({bondSize: e.target.value})}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} align="center" spacing={1}>
|
<Grid item xs={12} align="center" spacing={1}>
|
||||||
<br/>
|
|
||||||
<LocalizationProvider dateAdapter={DateFnsUtils}>
|
<LocalizationProvider dateAdapter={DateFnsUtils}>
|
||||||
<TimePicker
|
<TimePicker
|
||||||
ampm={false}
|
ampm={false}
|
||||||
@ -403,7 +416,6 @@ export default class MakerPage extends Component {
|
|||||||
track="inverted"
|
track="inverted"
|
||||||
value={this.state.minAmount ? this.state.minAmount : this.state.amount}
|
value={this.state.minAmount ? this.state.minAmount : this.state.amount}
|
||||||
step={this.state.amount/100}
|
step={this.state.amount/100}
|
||||||
getAriaValueText={this.bondSizeText}
|
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
valueLabelFormat={(x) => (x+" "+this.state.currencyCode)}
|
valueLabelFormat={(x) => (x+" "+this.state.currencyCode)}
|
||||||
marks={this.state.amount == null ?
|
marks={this.state.amount == null ?
|
||||||
@ -420,35 +432,6 @@ export default class MakerPage extends Component {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} align="center" spacing={1}>
|
|
||||||
<FormControl align="center">
|
|
||||||
<FormHelperText>
|
|
||||||
<Tooltip enterTouchDelay="0" title={"COMING SOON - Increase for a higher safety assurance"}>
|
|
||||||
<div align="center" style={{display:'flex',flexWrap:'wrap', transform: 'translate(20%, 0)'}}>
|
|
||||||
<LockIcon sx={{height:20,width:20}}/> Fidelity Bond Size
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
</FormHelperText>
|
|
||||||
|
|
||||||
<Slider
|
|
||||||
disabled
|
|
||||||
sx={{width:220, align:"center"}}
|
|
||||||
aria-label="Bond Size (%)"
|
|
||||||
defaultValue={1}
|
|
||||||
getAriaValueText={this.bondSizeText}
|
|
||||||
valueLabelDisplay="auto"
|
|
||||||
valueLabelFormat={(x) => (x+'%')}
|
|
||||||
step={0.5}
|
|
||||||
marks={[{value: 1,label: '1%'},{value: 3,label: '3%'},{value: 5,label: '5%'},{value: 9,label: '9%'},{value: 15,label: '15%'}]}
|
|
||||||
min={1}
|
|
||||||
max={15}
|
|
||||||
onChange={this.handleSliderBondSizeChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid item xs={12} align="center" spacing={1}>
|
<Grid item xs={12} align="center" spacing={1}>
|
||||||
<Tooltip enterTouchDelay="0" title={"COMING SOON - High risk! Limited to "+ this.maxBondlessSats/1000 +"K Sats"}>
|
<Tooltip enterTouchDelay="0" title={"COMING SOON - High risk! Limited to "+ this.maxBondlessSats/1000 +"K Sats"}>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user