Add onchain logics pt2

This commit is contained in:
Reckless_Satoshi 2022-06-06 13:37:51 -07:00
parent 8d0b518222
commit cf82a4d6ae
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
7 changed files with 83 additions and 15 deletions

View File

@ -113,9 +113,9 @@ MAX_SWAP_FEE = 0.1
# Liquidity split point (LN/onchain) at which we use MAX_SWAP_FEE
MAX_SWAP_POINT = 0
# Shape of fee to available liquidity curve. Only 'linear' implemented.
SWAP_FEE_ = 'linear'
SWAP_FEE_SHAPE = 'linear'
# Min amount allowed for Swap
MIN_SWAP_AMOUNT = 800000
MIN_SWAP_AMOUNT = 50000
# Reward tip. Reward for every finished trade in the referral program (Satoshis)
REWARD_TIP = 100

View File

@ -305,7 +305,7 @@ class LNNode:
lnpayment.num_satoshis * float(config("PROPORTIONAL_ROUTING_FEE_LIMIT")),
float(config("MIN_FLAT_ROUTING_FEE_LIMIT_REWARD")),
)) # 200 ppm or 10 sats
timeout_seconds = int(config("PAYOUT_TIMEOUT_SECONDS"))
timeout_seconds = int(config("REWARDS_TIMEOUT_SECONDS"))
request = routerrpc.SendPaymentRequest(payment_request=lnpayment.invoice,
fee_limit_sat=fee_limit_sat,
timeout_seconds=timeout_seconds)

View File

@ -4,7 +4,7 @@ from django.utils import timezone
from api.lightning.node import LNNode
from django.db.models import Q
from api.models import Order, LNPayment, MarketTick, User, Currency
from api.models import OnchainPayment, Order, LNPayment, MarketTick, User, Currency
from api.tasks import send_message
from decouple import config
@ -494,10 +494,46 @@ class Logics:
order.save()
return True, None
def compute_swap_fee_rate(balance):
shape = str(config('SWAP_FEE_SHAPE'))
if shape == "linear":
MIN_SWAP_FEE = float(config('MIN_SWAP_FEE'))
MIN_POINT = float(config('MIN_POINT'))
MAX_SWAP_FEE = float(config('MAX_SWAP_FEE'))
MAX_POINT = float(config('MAX_POINT'))
if balance.onchain_fraction > MIN_POINT:
swap_fee_rate = MIN_SWAP_FEE
else:
slope = (MAX_SWAP_FEE - MIN_SWAP_FEE) / (MAX_POINT - MIN_POINT)
swap_fee_rate = slope * (balance.onchain_fraction - MAX_POINT) + MAX_SWAP_FEE
return swap_fee_rate
@classmethod
def create_onchain_payment(cls, order, estimate_sats):
'''
Creates an empty OnchainPayment for order.payout_tx.
It sets the fees to be applied to this order if onchain Swap is used.
If the user submits a LN invoice instead. The returned OnchainPayment goes unused.
'''
onchain_payment = OnchainPayment.objects.create()
onchain_payment.suggested_mining_fee_rate = LNNode.estimate_fee(amount_sats=estimate_sats)
onchain_payment.swap_fee_rate = cls.compute_swap_fee_rate(onchain_payment.balance)
onchain_payment.save()
order.payout_tx = onchain_payment
order.save()
return True, None
@classmethod
def payout_amount(cls, order, user):
"""Computes buyer invoice amount. Uses order.last_satoshis,
that is the final trade amount set at Taker Bond time"""
that is the final trade amount set at Taker Bond time
Adds context for onchain swap.
"""
if not cls.is_buyer(order, user):
return False, None
if user == order.maker:
fee_fraction = FEE * MAKER_FEE_SPLIT
@ -508,10 +544,25 @@ class Logics:
reward_tip = int(config('REWARD_TIP')) if user.profile.is_referred else 0
if cls.is_buyer(order, user):
invoice_amount = round(order.last_satoshis - fee_sats - reward_tip) # Trading fee to buyer is charged here.
context = {}
# context necessary for the user to submit a LN invoice
context["invoice_amount"] = round(order.last_satoshis - fee_sats - reward_tip) # Trading fee to buyer is charged here.
return True, {"invoice_amount": invoice_amount}
# context necessary for the user to submit an onchain address
MIN_SWAP_AMOUNT = int(config("MIN_SWAP_AMOUNT"))
if context["invoice_amount"] < MIN_SWAP_AMOUNT:
context["swap_allowed"] = False
return True, context
if order.payout_tx == None:
cls.create_onchain_payment(order, estimate_sats=context["invoice_amount"])
context["swap_allowed"] = True
context["suggested_mining_fee_rate"] = order.payout_tx.suggested_mining_fee_rate
context["swap_fee_rate"] = order.payout_tx.swap_fee_rate
return True, context
@classmethod
def escrow_amount(cls, order, user):

View File

@ -219,10 +219,11 @@ class OnchainPayment(models.Model):
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)
balance = models.ForeignKey(BalanceLog,
related_name="balance",
on_delete=models.SET_NULL,
default=BalanceLog.objects.create)
swap_fee_rate = models.DecimalField(max_digits=4,
decimal_places=2,
default=2,
@ -452,7 +453,16 @@ class Order(models.Model):
# buyer payment LN invoice
payout = models.OneToOneField(
LNPayment,
related_name="order_paid",
related_name="order_paid_LN",
on_delete=models.SET_NULL,
null=True,
default=None,
blank=True,
)
payout_tx = models.OneToOneField(
OnchainPayment,
related_name="order_paid_TX",
on_delete=models.SET_NULL,
null=True,
default=None,

View File

@ -54,6 +54,10 @@ class UpdateOrderSerializer(serializers.Serializer):
allow_null=True,
allow_blank=True,
default=None)
address = serializers.CharField(max_length=100,
allow_null=True,
allow_blank=True,
default=None)
statement = serializers.CharField(max_length=10000,
allow_null=True,
allow_blank=True,
@ -63,6 +67,7 @@ class UpdateOrderSerializer(serializers.Serializer):
"pause",
"take",
"update_invoice",
"update_address",
"submit_statement",
"dispute",
"cancel",
@ -79,6 +84,7 @@ class UpdateOrderSerializer(serializers.Serializer):
default=None,
)
amount = serializers.DecimalField(max_digits=18, decimal_places=8, allow_null=True, required=False, default=None)
mining_fee_rate = serializers.DecimalField(max_digits=6, decimal_places=3, allow_null=True, required=False, default=None)
class UserGenSerializer(serializers.Serializer):
# Mandatory fields

View File

@ -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("REWARDS_TIMEOUT_SECONDS"))
timeout_seconds = int(config("PAYOUT_TIMEOUT_SECONDS"))
request = LNNode.routerrpc.SendPaymentRequest(
payment_request=lnpayment.invoice,

View File

@ -420,6 +420,7 @@ class OrderView(viewsets.ViewSet):
action = serializer.data.get("action")
invoice = serializer.data.get("invoice")
address = serializer.data.get("address")
mining_fee_rate = serializer.data.get("mining_fee_rate")
statement = serializer.data.get("statement")
rating = serializer.data.get("rating")
@ -469,7 +470,7 @@ class OrderView(viewsets.ViewSet):
# 2.b) If action is 'update invoice'
if action == "update_address":
valid, context = Logics.update_address(order, request.user,
address)
address, mining_fee_rate)
if not valid:
return Response(context, status.HTTP_400_BAD_REQUEST)