mirror of
https://github.com/RoboSats/robosats.git
synced 2024-09-11 14:05:51 +03:00
Add onchain logics pt2
This commit is contained in:
parent
8d0b518222
commit
cf82a4d6ae
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user