Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix models decoupling #874

Merged
merged 2 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 5 additions & 18 deletions .env-sample
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,6 @@ MAKER_FEE_SPLIT=0.125
# Leaving the default value (20%) will grant the DevFund contributor badge.
DEVFUND = 0.2

# Bond size as percentage (%)
DEFAULT_BOND_SIZE = 3
MIN_BOND_SIZE = 1
MAX_BOND_SIZE = 15

# Time out penalty for canceling takers in SECONDS
PENALTY_TIMEOUT = 60
# Time between routing attempts of buyer invoice in MINUTES
Expand All @@ -109,9 +104,11 @@ DISABLE_ORDER_LOGS = False
# Coordinator activity limits
MAX_PUBLIC_ORDERS = 100

# Trade limits in satoshis
MIN_TRADE = 20000
MAX_TRADE = 5000000
# Coordinator Order size limits in Satoshi
# Minimum order size (must be bigger than DB constrain in /robosats/settings.py MIN_TRADE, currently 20_000 Sats)
MIN_ORDER_SIZE = 20000
# Minimum order size (must be smaller than DB constrain in /robosats/settings.py MAX_TRADE, currently 5_000_000 Sats)
MAX_ORDER_SIZE = 5000000

# For CLTV_expiry calculation
# Assume 8 min/block assumed
Expand All @@ -123,16 +120,6 @@ MAX_MINING_NETWORK_SPEEDUP_EXPECTED = 1.7
EXP_MAKER_BOND_INVOICE = 300
EXP_TAKER_BOND_INVOICE = 200

# Time a order is public in the book HOURS
DEFAULT_PUBLIC_ORDER_DURATION = 24
MAX_PUBLIC_ORDER_DURATION = 24
MIN_PUBLIC_ORDER_DURATION = 0.166

# Default time to provide a valid invoice and the trade escrow MINUTES
INVOICE_AND_ESCROW_DURATION = 180
# Time to confim chat and confirm fiat (time to Fiat Sent confirmation) HOURS
FIAT_EXCHANGE_DURATION = 24

# ROUTING
# Proportional routing fee limit (fraction of total payout: % / 100)
PROPORTIONAL_ROUTING_FEE_LIMIT = 0.001
Expand Down
27 changes: 12 additions & 15 deletions api/logics.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
ESCROW_USERNAME = config("ESCROW_USERNAME")
PENALTY_TIMEOUT = int(config("PENALTY_TIMEOUT"))

MIN_TRADE = int(config("MIN_TRADE"))
MAX_TRADE = int(config("MAX_TRADE"))
MIN_ORDER_SIZE = config("MIN_ORDER_SIZE", cast=int, default=20_000)
MAX_ORDER_SIZE = config("MAX_ORDER_SIZE", cast=int, default=5_000_000)

EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE"))
EXP_TAKER_BOND_INVOICE = int(config("EXP_TAKER_BOND_INVOICE"))
Expand All @@ -29,9 +29,6 @@
config("MAX_MINING_NETWORK_SPEEDUP_EXPECTED")
)

INVOICE_AND_ESCROW_DURATION = int(config("INVOICE_AND_ESCROW_DURATION"))
FIAT_EXCHANGE_DURATION = int(config("FIAT_EXCHANGE_DURATION"))


class Logics:
@classmethod
Expand Down Expand Up @@ -90,20 +87,20 @@ def validate_already_maker_or_taker(cls, user):
def validate_order_size(cls, order):
"""Validates if order size in Sats is within limits at t0"""
if not order.has_range:
if order.t0_satoshis > MAX_TRADE:
if order.t0_satoshis > MAX_ORDER_SIZE:
return False, {
"bad_request": "Your order is too big. It is worth "
+ "{:,}".format(order.t0_satoshis)
+ " Sats now, but the limit is "
+ "{:,}".format(MAX_TRADE)
+ "{:,}".format(MAX_ORDER_SIZE)
+ " Sats"
}
if order.t0_satoshis < MIN_TRADE:
if order.t0_satoshis < MIN_ORDER_SIZE:
return False, {
"bad_request": "Your order is too small. It is worth "
+ "{:,}".format(order.t0_satoshis)
+ " Sats now, but the limit is "
+ "{:,}".format(MIN_TRADE)
+ "{:,}".format(MIN_ORDER_SIZE)
+ " Sats"
}
elif order.has_range:
Expand All @@ -117,20 +114,20 @@ def validate_order_size(cls, order):
return False, {
"bad_request": "Maximum range amount must be at least 50 percent higher than the minimum amount"
}
elif max_sats > MAX_TRADE:
elif max_sats > MAX_ORDER_SIZE:
return False, {
"bad_request": "Your order maximum amount is too big. It is worth "
+ "{:,}".format(int(max_sats))
+ " Sats now, but the limit is "
+ "{:,}".format(MAX_TRADE)
+ "{:,}".format(MAX_ORDER_SIZE)
+ " Sats"
}
elif min_sats < MIN_TRADE:
elif min_sats < MIN_ORDER_SIZE:
return False, {
"bad_request": "Your order minimum amount is too small. It is worth "
+ "{:,}".format(int(min_sats))
+ " Sats now, but the limit is "
+ "{:,}".format(MIN_TRADE)
+ "{:,}".format(MIN_ORDER_SIZE)
+ " Sats"
}
elif min_sats < max_sats / 15:
Expand Down Expand Up @@ -590,7 +587,7 @@ def compute_swap_fee_rate(balance):
shape = str(config("SWAP_FEE_SHAPE"))

if shape == "linear":
MIN_SWAP_FEE = float(config("MIN_SWAP_FEE"))
MIN_SWAP_FEE = config("MIN_SWAP_FEE", cast=float, default=0.01)
MIN_POINT = float(config("MIN_POINT"))
MAX_SWAP_FEE = float(config("MAX_SWAP_FEE"))
MAX_POINT = float(config("MAX_POINT"))
Expand All @@ -603,7 +600,7 @@ def compute_swap_fee_rate(balance):
)

elif shape == "exponential":
MIN_SWAP_FEE = float(config("MIN_SWAP_FEE"))
MIN_SWAP_FEE = config("MIN_SWAP_FEE", cast=float, default=0.01)
MAX_SWAP_FEE = float(config("MAX_SWAP_FEE"))
SWAP_LAMBDA = float(config("SWAP_LAMBDA"))
swap_fee_rate = MIN_SWAP_FEE + (MAX_SWAP_FEE - MIN_SWAP_FEE) * math.exp(
Expand Down
4 changes: 2 additions & 2 deletions api/models/ln_payment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from decouple import config
from django.conf import settings
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
Expand Down Expand Up @@ -78,7 +78,7 @@ class FailureReason(models.IntegerChoices):
num_satoshis = models.PositiveBigIntegerField(
validators=[
MinValueValidator(100),
MaxValueValidator(1.5 * config("MAX_TRADE", cast=int, default=1_000_000)),
MaxValueValidator(1.5 * settings.MAX_TRADE),
]
)
# Routing budget in PPM
Expand Down
8 changes: 6 additions & 2 deletions api/models/market_tick.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class MarketTick(models.Model):
fee = models.DecimalField(
max_digits=4,
decimal_places=4,
default=config("FEE", cast=float, default=0),
default=0,
validators=[MinValueValidator(0), MaxValueValidator(1)],
)

Expand All @@ -71,7 +71,11 @@ def log_a_tick(order):
premium = 100 * (price / market_exchange_rate - 1)

market_tick = MarketTick.objects.create(
price=price, volume=volume, premium=premium, currency=order.currency
price=price,
volume=volume,
premium=premium,
currency=order.currency,
fee=config("FEE", cast=float, default=0),
)

return market_tick
Expand Down
17 changes: 4 additions & 13 deletions api/models/onchain_payment.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from decouple import config
from django.conf import settings
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
Expand All @@ -7,9 +7,6 @@

from control.models import BalanceLog

MAX_TRADE = config("MAX_TRADE", cast=int, default=1_000_000)
MIN_SWAP_AMOUNT = config("MIN_SWAP_AMOUNT", cast=int, default=1_000_000)


class OnchainPayment(models.Model):
class Concepts(models.IntegerChoices):
Expand Down Expand Up @@ -48,17 +45,11 @@ def get_balance():

num_satoshis = models.PositiveBigIntegerField(
null=True,
validators=[
MinValueValidator(0.5 * MIN_SWAP_AMOUNT),
MaxValueValidator(1.5 * MAX_TRADE),
],
validators=[MinValueValidator(0), MaxValueValidator(1.5 * settings.MAX_TRADE)],
)
sent_satoshis = models.PositiveBigIntegerField(
null=True,
validators=[
MinValueValidator(0.5 * MIN_SWAP_AMOUNT),
MaxValueValidator(1.5 * MAX_TRADE),
],
validators=[MinValueValidator(0), MaxValueValidator(1.5 * settings.MAX_TRADE)],
)
# fee in sats/vbyte with mSats decimals fee_msat
suggested_mining_fee_rate = models.DecimalField(
Expand Down Expand Up @@ -91,7 +82,7 @@ def get_balance():
swap_fee_rate = models.DecimalField(
max_digits=4,
decimal_places=2,
default=config("MIN_SWAP_FEE", cast=float, default=0.01) * 100,
default=1,
null=False,
blank=False,
)
Expand Down
38 changes: 21 additions & 17 deletions api/models/order.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import uuid

from decouple import config
from django.conf import settings
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.utils import timezone

MIN_TRADE = config("MIN_TRADE", cast=int, default=20_000)
MAX_TRADE = config("MAX_TRADE", cast=int, default=1_000_000)
FIAT_EXCHANGE_DURATION = config("FIAT_EXCHANGE_DURATION", cast=int, default=24)


class Order(models.Model):
class Types(models.IntegerChoices):
Expand Down Expand Up @@ -85,28 +82,30 @@ class ExpiryReasons(models.IntegerChoices):
# explicit
satoshis = models.PositiveBigIntegerField(
null=True,
validators=[MinValueValidator(MIN_TRADE), MaxValueValidator(MAX_TRADE)],
validators=[
MinValueValidator(settings.MIN_TRADE),
MaxValueValidator(settings.MAX_TRADE),
],
blank=True,
)
# optionally makers can choose the public order duration length (seconds)
public_duration = models.PositiveBigIntegerField(
default=60 * 60 * config("DEFAULT_PUBLIC_ORDER_DURATION", cast=int, default=24)
- 1,
default=60 * 60 * settings.DEFAULT_PUBLIC_ORDER_DURATION - 1,
null=False,
validators=[
MinValueValidator(
60 * 60 * config("MIN_PUBLIC_ORDER_DURATION", cast=float, default=0.166)
60 * 60 * settings.MIN_PUBLIC_ORDER_DURATION
), # Min is 10 minutes
MaxValueValidator(
60 * 60 * config("MAX_PUBLIC_ORDER_DURATION", cast=float, default=24)
60 * 60 * settings.MAX_PUBLIC_ORDER_DURATION
), # Max is 24 Hours
],
blank=False,
)

# optionally makers can choose the escrow lock / invoice submission step length (seconds)
escrow_duration = models.PositiveBigIntegerField(
default=60 * int(config("INVOICE_AND_ESCROW_DURATION")) - 1,
default=60 * settings.INVOICE_AND_ESCROW_DURATION - 1,
null=False,
validators=[
MinValueValidator(60 * 30), # Min is 30 minutes
Expand All @@ -119,24 +118,27 @@ class ExpiryReasons(models.IntegerChoices):
bond_size = models.DecimalField(
max_digits=4,
decimal_places=2,
default=config("DEFAULT_BOND_SIZE", cast=float, default=3),
default=settings.DEFAULT_BOND_SIZE,
null=False,
validators=[
MinValueValidator(config("MIN_BOND_SIZE", cast=float, default=1)), # 1 %
MaxValueValidator(config("MAX_BOND_SIZE", cast=float, default=1)), # 15 %
MinValueValidator(settings.MIN_BOND_SIZE), # 2 %
MaxValueValidator(settings.MAX_BOND_SIZE), # 15 %
],
blank=False,
)

# how many sats at creation and at last check (relevant for marked to market)
t0_satoshis = models.PositiveBigIntegerField(
null=True,
validators=[MinValueValidator(MIN_TRADE), MaxValueValidator(MAX_TRADE)],
validators=[
MinValueValidator(settings.MIN_TRADE),
MaxValueValidator(settings.MAX_TRADE),
],
blank=True,
) # sats at creation
last_satoshis = models.PositiveBigIntegerField(
null=True,
validators=[MinValueValidator(0), MaxValueValidator(MAX_TRADE * 2)],
validators=[MinValueValidator(0), MaxValueValidator(settings.MAX_TRADE * 2)],
blank=True,
) # sats last time checked. Weird if 2* trade max...
# timestamp of last_satoshis
Expand Down Expand Up @@ -267,8 +269,10 @@ def t_to_expire(self, status):
), # 'Waiting for trade collateral and buyer invoice'
7: int(self.escrow_duration), # 'Waiting only for seller trade collateral'
8: int(self.escrow_duration), # 'Waiting only for buyer invoice'
9: 60 * 60 * FIAT_EXCHANGE_DURATION, # 'Sending fiat - In chatroom'
10: 60 * 60 * FIAT_EXCHANGE_DURATION, # 'Fiat sent - In chatroom'
9: 60
* 60
* settings.FIAT_EXCHANGE_DURATION, # 'Sending fiat - In chatroom'
10: 60 * 60 * settings.FIAT_EXCHANGE_DURATION, # 'Fiat sent - In chatroom'
11: 1 * 24 * 60 * 60, # 'In dispute'
12: 0, # 'Collaboratively cancelled'
13: 100 * 24 * 60 * 60, # 'Sending satoshis to buyer'
Expand Down
10 changes: 4 additions & 6 deletions api/oas_schemas.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import textwrap

from decouple import config
from django.conf import settings
from drf_spectacular.utils import OpenApiExample, OpenApiParameter

from api.serializers import (
Expand All @@ -11,9 +12,6 @@

EXP_MAKER_BOND_INVOICE = int(config("EXP_MAKER_BOND_INVOICE"))
RETRY_TIME = int(config("RETRY_TIME"))
PUBLIC_DURATION = 60 * 60 * int(config("DEFAULT_PUBLIC_ORDER_DURATION")) - 1
ESCROW_DURATION = 60 * int(config("INVOICE_AND_ESCROW_DURATION"))
BOND_SIZE = int(config("DEFAULT_BOND_SIZE"))


class MakerViewSchema:
Expand All @@ -25,9 +23,9 @@ class MakerViewSchema:


Default values for the following fields if not specified:
- `public_duration` - **{PUBLIC_DURATION}**
- `escrow_duration` - **{ESCROW_DURATION}**
- `bond_size` - **{BOND_SIZE}**
- `public_duration` - **{settings.DEFAULT_PUBLIC_ORDER_DURATION}**
- `escrow_duration` - **{settings.INVOICE_AND_ESCROW_DURATION}**
- `bond_size` - **{settings.DEFAULT_BOND_SIZE}**
- `has_range` - **false**
- `premium` - **0**
"""
Expand Down
2 changes: 0 additions & 2 deletions api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from .models import MarketTick, Order

RETRY_TIME = int(config("RETRY_TIME"))
MIN_PUBLIC_ORDER_DURATION_SECS = 60 * 60 * float(config("MIN_PUBLIC_ORDER_DURATION"))
MAX_PUBLIC_ORDER_DURATION_SECS = 60 * 60 * float(config("MAX_PUBLIC_ORDER_DURATION"))


class InfoSerializer(serializers.Serializer):
Expand Down
Loading