Create Balance model and log task

This commit is contained in:
Reckless_Satoshi 2022-06-05 14:16:03 -07:00
parent 4ac3618fd7
commit f538d26355
No known key found for this signature in database
GPG Key ID: 9C4585B561315571
6 changed files with 136 additions and 14 deletions

View File

@ -93,7 +93,7 @@ FIAT_EXCHANGE_DURATION = 24
# ROUTING # ROUTING
# Proportional routing fee limit (fraction of total payout: % / 100) # Proportional routing fee limit (fraction of total payout: % / 100)
PROPORTIONAL_ROUTING_FEE_LIMIT = 0.0002 PROPORTIONAL_ROUTING_FEE_LIMIT = 0.001
# Base flat limit fee for routing in Sats (used only when proportional is lower than this) # Base flat limit fee for routing in Sats (used only when proportional is lower than this)
MIN_FLAT_ROUTING_FEE_LIMIT = 10 MIN_FLAT_ROUTING_FEE_LIMIT = 10
MIN_FLAT_ROUTING_FEE_LIMIT_REWARD = 2 MIN_FLAT_ROUTING_FEE_LIMIT_REWARD = 2
@ -101,6 +101,22 @@ MIN_FLAT_ROUTING_FEE_LIMIT_REWARD = 2
REWARDS_TIMEOUT_SECONDS = 60 REWARDS_TIMEOUT_SECONDS = 60
PAYOUT_TIMEOUT_SECONDS = 60 PAYOUT_TIMEOUT_SECONDS = 60
# REVERSE SUBMARINE SWAP PAYOUTS
# 4 parameters needed, min/max change and min/max balance points. E.g. If 25% or more of liquidity
# is onchain the fee for swap is 2% (minimum), if it is 12% fee is 6%, and for 0% fee is 10%.
# Minimum swap fee as fraction (2%)
MIN_SWAP_FEE = 0.02
# Liquidity split point (LN/onchain) at which we use MIN_SWAP_FEE
MIN_SWAP_POINT = 0.25
# Maximum swap fee as fraction (~10%)
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'
# Min amount allowed for Swap
MIN_SWAP_AMOUNT = 800000
# Reward tip. Reward for every finished trade in the referral program (Satoshis) # Reward tip. Reward for every finished trade in the referral program (Satoshis)
REWARD_TIP = 100 REWARD_TIP = 100
# Fraction rewarded to user from the slashed bond of a counterpart. # Fraction rewarded to user from the slashed bond of a counterpart.

View File

@ -1,4 +1,4 @@
import grpc, os, hashlib, secrets import grpc, os, hashlib, secrets, ring
from . import lightning_pb2 as lnrpc, lightning_pb2_grpc as lightningstub from . import lightning_pb2 as lnrpc, lightning_pb2_grpc as lightningstub
from . import invoices_pb2 as invoicesrpc, invoices_pb2_grpc as invoicesstub from . import invoices_pb2 as invoicesrpc, invoices_pb2_grpc as invoicesstub
from . import router_pb2 as routerrpc, router_pb2_grpc as routerstub from . import router_pb2 as routerrpc, router_pb2_grpc as routerstub
@ -8,7 +8,6 @@ from base64 import b64decode
from datetime import timedelta, datetime from datetime import timedelta, datetime
from django.utils import timezone from django.utils import timezone
from api.models import LNPayment from api.models import LNPayment
####### #######
@ -67,6 +66,52 @@ class LNNode:
MACAROON.hex())]) MACAROON.hex())])
return response return response
@classmethod
def estimate_fee(cls, amount_sats, target_conf=2, min_confs=1):
"""Returns estimated fee for onchain payouts"""
# We assume segwit. Use robosats donation address (shortcut so there is no need to have user input)
request = lnrpc.EstimateFeeRequest(AddrToAmount={'bc1q3cpp7ww92n6zp04hv40kd3eyy5avgughx6xqnx':amount_sats},
target_conf=target_conf,
min_confs=min_confs,
spend_unconfirmed=False)
response = cls.lightningstub.EstimateFee(request,
metadata=[("macaroon",
MACAROON.hex())])
return {'mining_fee_sats': response.fee_sat, 'mining_fee_rate': response.sat_per_vbyte}
wallet_balance_cache = {}
@ring.dict(wallet_balance_cache, expire=10) # keeps in cache for 10 seconds
@classmethod
def wallet_balance(cls):
"""Returns onchain balance"""
request = lnrpc.WalletBalanceRequest()
response = cls.lightningstub.WalletBalance(request,
metadata=[("macaroon",
MACAROON.hex())])
print(response)
return {'total_balance': response.total_balance,
'confirmed_balance': response.confirmed_balance,
'unconfirmed_balance': response.unconfirmed_balance}
channel_balance_cache = {}
@ring.dict(channel_balance_cache, expire=10) # keeps in cache for 10 seconds
@classmethod
def channel_balance(cls):
"""Returns channels balance"""
request = lnrpc.ChannelBalanceRequest()
response = cls.lightningstub.ChannelBalance(request,
metadata=[("macaroon",
MACAROON.hex())])
print(response)
return {'local_balance': response.local_balance.sat,
'remote_balance': response.remote_balance.sat,
'unsettled_local_balance': response.unsettled_local_balance.sat,
'unsettled_remote_balance': response.unsettled_remote_balance.sat}
@classmethod @classmethod
def cancel_return_hold_invoice(cls, payment_hash): def cancel_return_hold_invoice(cls, payment_hash):
"""Cancels or returns a hold invoice""" """Cancels or returns a hold invoice"""

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from control.models import AccountingDay, AccountingMonth, Dispute from control.models import AccountingDay, AccountingMonth, BalanceLog
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
# Register your models here. # Register your models here.
@ -51,3 +51,34 @@ class AccountingMonthAdmin(ImportExportModelAdmin):
) )
change_links = ["month"] change_links = ["month"]
search_fields = ["month"] search_fields = ["month"]
@admin.register(BalanceLog)
class BalanceLogAdmin(ImportExportModelAdmin):
list_display = (
"time",
"total",
"onchain_fraction",
"onchain_total",
"onchain_confirmed",
"onchain_unconfirmed",
"ln_local",
"ln_remote",
"ln_local_unsettled",
"ln_remote_unsettled",
)
readonly_fields = [
"time",
"total",
"onchain_fraction",
"onchain_total",
"onchain_confirmed",
"onchain_unconfirmed",
"ln_local",
"ln_remote",
"ln_local_unsettled",
"ln_remote_unsettled",
]
change_links = ["time"]
search_fields = ["time"]

View File

@ -1,6 +1,8 @@
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from api.lightning.node import LNNode
class AccountingDay(models.Model): class AccountingDay(models.Model):
day = models.DateTimeField(primary_key=True, auto_now=False, auto_now_add=False) day = models.DateTimeField(primary_key=True, auto_now=False, auto_now_add=False)
@ -36,8 +38,6 @@ class AccountingDay(models.Model):
# Rewards claimed on day # Rewards claimed on day
rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False) rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
class AccountingMonth(models.Model): class AccountingMonth(models.Model):
month = models.DateTimeField(primary_key=True, auto_now=False, auto_now_add=False) month = models.DateTimeField(primary_key=True, auto_now=False, auto_now_add=False)
@ -73,5 +73,19 @@ class AccountingMonth(models.Model):
# Rewards claimed on day # Rewards claimed on day
rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False) rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
class BalanceLog(models.Model):
time = models.DateTimeField(primary_key=True, default=timezone.now)
# Every field is denominated in Sats
total = models.PositiveBigIntegerField(default=lambda : LNNode.wallet_balance()['total_balance'] + LNNode.channel_balance()['local_balance'])
onchain_fraction = models.DecimalField(max_digits=5, decimal_places=5, default=lambda : (LNNode.wallet_balance()['total_balance'] + LNNode.channel_balance()['local_balance']) / LNNode.wallet_balance()['total_balance'])
onchain_total = models.PositiveBigIntegerField(default=lambda : LNNode.wallet_balance()['total_balance'])
onchain_confirmed = models.PositiveBigIntegerField(default=lambda : LNNode.wallet_balance()['confirmed_balance'])
onchain_unconfirmed = models.PositiveBigIntegerField(default=lambda : LNNode.wallet_balance()['unconfirmed_balance'])
ln_local = models.PositiveBigIntegerField(default=lambda : LNNode.channel_balance()['local_balance'])
ln_remote = models.PositiveBigIntegerField(default=lambda : LNNode.channel_balance()['remote_balance'])
ln_local_unsettled = models.PositiveBigIntegerField(default=lambda : LNNode.channel_balance()['unsettled_local_balance'])
ln_remote_unsettled = models.PositiveBigIntegerField(default=lambda : LNNode.channel_balance()['unsettled_remote_balance'])
class Dispute(models.Model): class Dispute(models.Model):
pass pass

View File

@ -1,10 +1,4 @@
from celery import shared_task from celery import shared_task
from api.models import Order, LNPayment, Profile, MarketTick
from control.models import AccountingDay, AccountingMonth
from django.utils import timezone
from datetime import timedelta
from django.db.models import Sum
from decouple import config
@shared_task(name="do_accounting") @shared_task(name="do_accounting")
def do_accounting(): def do_accounting():
@ -12,6 +6,13 @@ def do_accounting():
Does all accounting from the beginning of time Does all accounting from the beginning of time
''' '''
from api.models import Order, LNPayment, Profile, MarketTick
from control.models import AccountingDay
from django.utils import timezone
from datetime import timedelta
from django.db.models import Sum
from decouple import config
all_payments = LNPayment.objects.all() all_payments = LNPayment.objects.all()
all_ticks = MarketTick.objects.all() all_ticks = MarketTick.objects.all()
today = timezone.now().date() today = timezone.now().date()
@ -110,3 +111,14 @@ def do_accounting():
day = day + timedelta(days=1) day = day + timedelta(days=1)
return result return result
@shared_task(name="compute_node_balance", ignore_result=True)
def compute_node_balance():
'''
Queries LND for channel and wallet balance
'''
from control.models import BalanceLog
BalanceLog.objects.create()
return

View File

@ -55,6 +55,10 @@ app.conf.beat_schedule = {
"task": "cache_external_market_prices", "task": "cache_external_market_prices",
"schedule": timedelta(seconds=60), "schedule": timedelta(seconds=60),
}, },
"compute-node-balance": { # Logs LND channel and wallet balance
"task":"compute_node_balance",
"schedule": timedelta(minutes=15),
}
} }
app.conf.timezone = "UTC" app.conf.timezone = "UTC"