diff --git a/.gitignore b/.gitignore index 96ea0573..21c16b36 100755 --- a/.gitignore +++ b/.gitignore @@ -635,3 +635,5 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd +# Django +*migrations* diff --git a/api/models.py b/api/models.py index 71a83623..60ed9c1a 100644 --- a/api/models.py +++ b/api/models.py @@ -1,3 +1,71 @@ from django.db import models +from django.contrib.auth.models import User +from django.core.validators import MaxValueValidator, MinValueValidator -# Create your models here. +############################# +# TODO +# Load hparams from .env file + +min_satoshis_trade = 10*1000 +max_satoshis_trade = 500*1000 + +class Order(models.Model): + + class Types(models.IntegerChoices): + BUY = 0, 'BUY' + SELL = 1, 'SELL' + + class Currencies(models.IntegerChoices): + USD = 1, 'USD' + EUR = 2, 'EUR' + ETH = 3, 'ETH' + + class Status(models.TextChoices): + WFB = 0, 'Waiting for bond' + PUB = 1, 'Published in order book' + DEL = 2, 'Deleted from order book' + TAK = 3, 'Taken' + UCA = 4, 'Unilaterally cancelled' + RET = 5, 'Returned to order book' # Probably same as 1 in most cases. + WF2 = 6, 'Waiting for trade collateral and buyer invoice' + WTC = 7, 'Waiting only for trade collateral' + WBI = 8, 'Waiting only for buyer invoice' + EXF = 9, 'Exchanging fiat / In chat' + CCA = 10, 'Collaboratively cancelled' + FSE = 11, 'Fiat sent' + FCO = 12, 'Fiat confirmed' + SUC = 13, 'Sucessfully settled' + FAI = 14, 'Failed lightning network routing' + UPI = 15, 'Updated invoice' + DIS = 16, 'In dispute' + MLD = 17, 'Maker lost dispute' + TLD = 18, 'Taker lost dispute' + EXP = 19, 'Expired' + + # order info, id = models.CharField(max_length=64, unique=True, null=False) + status = models.PositiveSmallIntegerField(choices=Status.choices, default=Status.WFB) + created_at = models.DateTimeField(auto_now_add=True) + + # order details + type = models.PositiveSmallIntegerField(choices=Types.choices, null=False) + currency = models.PositiveSmallIntegerField(choices=Currencies.choices, null=False) + amount = models.DecimalField(max_digits=9, decimal_places=4, validators=[MinValueValidator(0.00001)]) + premium = models.DecimalField(max_digits=3, decimal_places=2, default=0, null=True, validators=[MinValueValidator(-100), MaxValueValidator(1000)]) + satoshis = models.PositiveBigIntegerField(null=True, validators=[MinValueValidator(min_satoshis_trade), MaxValueValidator(max_satoshis_trade)]) + + # order participants + maker = models.ForeignKey(User, related_name='maker', on_delete=models.SET_NULL, null=True, default=None) # unique = True, a maker can only make one order + taker = models.ForeignKey(User, related_name='taker', on_delete=models.SET_NULL, null=True, default=None) # unique = True, a taker can only take one order + + # order collateral + has_maker_bond = models.BooleanField(default=False, null=False) + has_taker_bond = models.BooleanField(default=False, null=False) + has_trade_collat = models.BooleanField(default=False, null=False) + + maker_bond_secret = models.CharField(max_length=300, unique=False, null=True, default=None) + taker_bond_secret = models.CharField(max_length=300, unique=False, null=True, default=None) + trade_collat_secret = models.CharField(max_length=300, unique=False, null=True, default=None) + + # buyer payment LN invoice + has_invoice = models.BooleanField(default=False, null=False) # has invoice and is valid + invoice = models.CharField(max_length=300, unique=False, null=True, default=None) diff --git a/api/serializers.py b/api/serializers.py new file mode 100644 index 00000000..9435ecdd --- /dev/null +++ b/api/serializers.py @@ -0,0 +1,12 @@ +from rest_framework import serializers +from .models import Order + +class OrderSerializer(serializers.ModelSerializer): + class Meta: + model = Order + fields = ('id','status','created_at','type','currency','amount','premium','satoshis','maker') + +class MakeOrderSerializer(serializers.ModelSerializer): + class Meta: + model = Order + fields = ('type','currency','amount','premium','satoshis') \ No newline at end of file diff --git a/api/urls.py b/api/urls.py new file mode 100644 index 00000000..2ddd2340 --- /dev/null +++ b/api/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from .views import MakeOrder + +urlpatterns = [ + path('make/', MakeOrder.as_view()) + ] \ No newline at end of file diff --git a/api/views.py b/api/views.py index 91ea44a2..4f68e242 100644 --- a/api/views.py +++ b/api/views.py @@ -1,3 +1,40 @@ -from django.shortcuts import render +from rest_framework import generics, status +from rest_framework.views import APIView +from rest_framework.response import Response + +from .serializers import OrderSerializer, MakeOrderSerializer +from .models import Order # Create your views here. + +class MakeOrder(APIView): + serializer_class = MakeOrderSerializer + + def post(self,request, format=None): + + serializer = self.serializer_class(data=request.data) + print(serializer) + if serializer.is_valid(): + otype = serializer.data.get('type') + currency = serializer.data.get('currency') + amount = serializer.data.get('amount') + premium = serializer.data.get('premium') + satoshis = serializer.data.get('satoshis') + + ################# + # TODO + # query if the user is already a maker or taker, return error + + # Creates a new order in db + order = Order( + type=otype, + currency=currency, + amount=amount, + premium=premium, + satoshis=satoshis) + order.save() + + if not serializer.is_valid(): + return Response(status=status.HTTP_400_BAD_REQUEST) + + return Response(OrderSerializer(order).data, status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/robosats/settings.py b/robosats/settings.py index c50c5079..8617533e 100644 --- a/robosats/settings.py +++ b/robosats/settings.py @@ -37,6 +37,8 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'rest_framework', + 'api', ] MIDDLEWARE = [ diff --git a/robosats/urls.py b/robosats/urls.py index 83b304db..dde1abba 100644 --- a/robosats/urls.py +++ b/robosats/urls.py @@ -14,8 +14,9 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), -] + path('api/', include('api.urls')), + ]