mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Add onchain logics pt1
This commit is contained in:
parent
f538d26355
commit
8d0b518222
@ -8,7 +8,7 @@ from base64 import b64decode
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from django.utils import timezone
|
||||
from api.models import LNPayment
|
||||
|
||||
|
||||
#######
|
||||
# Should work with LND (c-lightning in the future if there are features that deserve the work)
|
||||
@ -176,6 +176,8 @@ class LNNode:
|
||||
@classmethod
|
||||
def validate_hold_invoice_locked(cls, lnpayment):
|
||||
"""Checks if hold invoice is locked"""
|
||||
from api.models import LNPayment
|
||||
|
||||
request = invoicesrpc.LookupInvoiceMsg(
|
||||
payment_hash=bytes.fromhex(lnpayment.payment_hash))
|
||||
response = cls.invoicesstub.LookupInvoiceV2(request,
|
||||
@ -296,7 +298,8 @@ class LNNode:
|
||||
@classmethod
|
||||
def pay_invoice(cls, lnpayment):
|
||||
"""Sends sats. Used for rewards payouts"""
|
||||
|
||||
from api.models import LNPayment
|
||||
|
||||
fee_limit_sat = int(
|
||||
max(
|
||||
lnpayment.num_satoshis * float(config("PROPORTIONAL_ROUTING_FEE_LIMIT")),
|
||||
|
@ -17,8 +17,11 @@ from decouple import config
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
from control.models import BalanceLog
|
||||
|
||||
MIN_TRADE = int(config("MIN_TRADE"))
|
||||
MAX_TRADE = int(config("MAX_TRADE"))
|
||||
MIN_SWAP_AMOUNT = int(config("MIN_SWAP_AMOUNT"))
|
||||
FEE = float(config("FEE"))
|
||||
DEFAULT_BOND_SIZE = float(config("DEFAULT_BOND_SIZE"))
|
||||
|
||||
@ -118,7 +121,7 @@ class LNPayment(models.Model):
|
||||
blank=True)
|
||||
num_satoshis = models.PositiveBigIntegerField(validators=[
|
||||
MinValueValidator(100),
|
||||
MaxValueValidator(MAX_TRADE * (1 + DEFAULT_BOND_SIZE + FEE)),
|
||||
MaxValueValidator(1.5 * MAX_TRADE),
|
||||
])
|
||||
# Fee in sats with mSats decimals fee_msat
|
||||
fee = models.DecimalField(max_digits=10, decimal_places=3, default=0, null=False, blank=False)
|
||||
@ -163,6 +166,96 @@ class LNPayment(models.Model):
|
||||
# We created a truncated property for display 'hash'
|
||||
return truncatechars(self.payment_hash, 10)
|
||||
|
||||
class OnchainPayment(models.Model):
|
||||
|
||||
class Concepts(models.IntegerChoices):
|
||||
PAYBUYER = 3, "Payment to buyer"
|
||||
|
||||
class Status(models.IntegerChoices):
|
||||
CREAT = 0, "Created" # User was given platform fees and suggested mining fees
|
||||
VALID = 1, "Valid" # Valid onchain address submitted
|
||||
MEMPO = 2, "In mempool" # Tx is sent to mempool
|
||||
CONFI = 3, "Confirmed" # Tx is confirme +2 blocks
|
||||
|
||||
# payment use details
|
||||
concept = models.PositiveSmallIntegerField(choices=Concepts.choices,
|
||||
null=False,
|
||||
default=Concepts.PAYBUYER)
|
||||
status = models.PositiveSmallIntegerField(choices=Status.choices,
|
||||
null=False,
|
||||
default=Status.VALID)
|
||||
|
||||
# payment info
|
||||
address = models.CharField(max_length=100,
|
||||
unique=False,
|
||||
default=None,
|
||||
null=True,
|
||||
blank=True)
|
||||
|
||||
txid = models.CharField(max_length=64,
|
||||
unique=True,
|
||||
null=True,
|
||||
default=None,
|
||||
blank=True)
|
||||
|
||||
num_satoshis = models.PositiveBigIntegerField(validators=[
|
||||
MinValueValidator(0.7 * MIN_SWAP_AMOUNT),
|
||||
MaxValueValidator(1.5 * MAX_TRADE),
|
||||
])
|
||||
|
||||
# fee in sats/vbyte with mSats decimals fee_msat
|
||||
suggested_mining_fee_rate = models.DecimalField(max_digits=6,
|
||||
decimal_places=3,
|
||||
default=1.05,
|
||||
null=False,
|
||||
blank=False)
|
||||
mining_fee_rate = models.DecimalField(max_digits=6,
|
||||
decimal_places=3,
|
||||
default=1.05,
|
||||
null=False,
|
||||
blank=False)
|
||||
mining_fee_sats = models.PositiveBigIntegerField(default=0,
|
||||
null=False,
|
||||
blank=False)
|
||||
|
||||
# platform onchain/channels balance at creattion, swap fee rate as percent of total volume
|
||||
node_balance = models.ForeignKey(BalanceLog,
|
||||
related_name="balance",
|
||||
on_delete=models.SET_NULL,
|
||||
null=True)
|
||||
swap_fee_rate = models.DecimalField(max_digits=4,
|
||||
decimal_places=2,
|
||||
default=2,
|
||||
null=False,
|
||||
blank=False)
|
||||
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
|
||||
# involved parties
|
||||
receiver = models.ForeignKey(User,
|
||||
related_name="tx_receiver",
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
default=None)
|
||||
|
||||
def __str__(self):
|
||||
if self.txid:
|
||||
txname = str(self.txid)[:8]
|
||||
else:
|
||||
txname = str(self.id)
|
||||
|
||||
return f"TX-{txname}: {self.Concepts(self.concept).label} - {self.Status(self.status).label}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Lightning payment"
|
||||
verbose_name_plural = "Lightning payments"
|
||||
|
||||
@property
|
||||
def hash(self):
|
||||
# Payment hash is the primary key of LNpayments
|
||||
# However it is too long for the admin panel.
|
||||
# We created a truncated property for display 'hash'
|
||||
return truncatechars(self.payment_hash, 10)
|
||||
|
||||
class Order(models.Model):
|
||||
|
||||
|
@ -79,7 +79,7 @@ def follow_send_payment(hash):
|
||||
float(config("PROPORTIONAL_ROUTING_FEE_LIMIT")),
|
||||
float(config("MIN_FLAT_ROUTING_FEE_LIMIT")),
|
||||
)) # 1000 ppm or 10 sats
|
||||
timeout_seconds = int(config("REWARRDS_TIMEOUT_SECONDS"))
|
||||
timeout_seconds = int(config("REWARDS_TIMEOUT_SECONDS"))
|
||||
|
||||
request = LNNode.routerrpc.SendPaymentRequest(
|
||||
payment_request=lnpayment.invoice,
|
||||
|
21
api/utils.py
21
api/utils.py
@ -1,8 +1,7 @@
|
||||
import requests, ring, os
|
||||
from decouple import config
|
||||
import numpy as np
|
||||
import requests
|
||||
|
||||
import coinaddrvalidator as addr
|
||||
from api.models import Order
|
||||
|
||||
def get_tor_session():
|
||||
@ -12,6 +11,24 @@ def get_tor_session():
|
||||
'https': 'socks5://127.0.0.1:9050'}
|
||||
return session
|
||||
|
||||
def validate_onchain_address(address):
|
||||
'''
|
||||
Validates an onchain address
|
||||
'''
|
||||
|
||||
validation = addr.validate('btc', address.encode('utf-8'))
|
||||
|
||||
if not validation.valid:
|
||||
return False
|
||||
|
||||
NETWORK = str(config('NETWORK'))
|
||||
if NETWORK == 'mainnet':
|
||||
if validation.network == 'main':
|
||||
return True
|
||||
elif NETWORK == 'testnet':
|
||||
if validation.network == 'test':
|
||||
return True
|
||||
|
||||
market_cache = {}
|
||||
@ring.dict(market_cache, expire=3) # keeps in cache for 3 seconds
|
||||
def get_exchange_rates(currencies):
|
||||
|
10
api/views.py
10
api/views.py
@ -416,9 +416,10 @@ class OrderView(viewsets.ViewSet):
|
||||
order = Order.objects.get(id=order_id)
|
||||
|
||||
# action is either 1)'take', 2)'confirm', 3)'cancel', 4)'dispute' , 5)'update_invoice'
|
||||
# 6)'submit_statement' (in dispute), 7)'rate_user' , 'rate_platform'
|
||||
# 5.b)'update_address' 6)'submit_statement' (in dispute), 7)'rate_user' , 8)'rate_platform'
|
||||
action = serializer.data.get("action")
|
||||
invoice = serializer.data.get("invoice")
|
||||
address = serializer.data.get("address")
|
||||
statement = serializer.data.get("statement")
|
||||
rating = serializer.data.get("rating")
|
||||
|
||||
@ -464,6 +465,13 @@ class OrderView(viewsets.ViewSet):
|
||||
invoice)
|
||||
if not valid:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 2.b) If action is 'update invoice'
|
||||
if action == "update_address":
|
||||
valid, context = Logics.update_address(order, request.user,
|
||||
address)
|
||||
if not valid:
|
||||
return Response(context, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# 3) If action is cancel
|
||||
elif action == "cancel":
|
||||
|
@ -25,4 +25,5 @@ psycopg2==2.9.3
|
||||
SQLAlchemy==1.4.31
|
||||
django-import-export==2.7.1
|
||||
requests[socks]
|
||||
python-gnupg==0.4.9
|
||||
python-gnupg==0.4.9
|
||||
coinaddrvalidator==1.1.3
|
Loading…
Reference in New Issue
Block a user