mirror of
https://github.com/RoboSats/robosats.git
synced 2024-12-14 03:16:24 +00:00
Fix invoice payouts. Add onchain summary to accounting days.
This commit is contained in:
parent
5c87c5ad85
commit
43b85d79d4
@ -93,7 +93,7 @@ class LNNode:
|
|||||||
response = cls.lightningstub.WalletBalance(request,
|
response = cls.lightningstub.WalletBalance(request,
|
||||||
metadata=[("macaroon",
|
metadata=[("macaroon",
|
||||||
MACAROON.hex())])
|
MACAROON.hex())])
|
||||||
print(response)
|
|
||||||
return {'total_balance': response.total_balance,
|
return {'total_balance': response.total_balance,
|
||||||
'confirmed_balance': response.confirmed_balance,
|
'confirmed_balance': response.confirmed_balance,
|
||||||
'unconfirmed_balance': response.unconfirmed_balance}
|
'unconfirmed_balance': response.unconfirmed_balance}
|
||||||
@ -108,7 +108,7 @@ class LNNode:
|
|||||||
metadata=[("macaroon",
|
metadata=[("macaroon",
|
||||||
MACAROON.hex())])
|
MACAROON.hex())])
|
||||||
|
|
||||||
print(response)
|
|
||||||
return {'local_balance': response.local_balance.sat,
|
return {'local_balance': response.local_balance.sat,
|
||||||
'remote_balance': response.remote_balance.sat,
|
'remote_balance': response.remote_balance.sat,
|
||||||
'unsettled_local_balance': response.unsettled_local_balance.sat,
|
'unsettled_local_balance': response.unsettled_local_balance.sat,
|
||||||
@ -208,22 +208,17 @@ class LNNode:
|
|||||||
metadata=[("macaroon",
|
metadata=[("macaroon",
|
||||||
MACAROON.hex())
|
MACAROON.hex())
|
||||||
])
|
])
|
||||||
print("status here")
|
|
||||||
print(response.state)
|
|
||||||
|
|
||||||
# TODO ERROR HANDLING
|
|
||||||
# Will fail if 'unable to locate invoice'. Happens if invoice expiry
|
# Will fail if 'unable to locate invoice'. Happens if invoice expiry
|
||||||
# time has passed (but these are 15% padded at the moment). Should catch it
|
# time has passed (but these are 15% padded at the moment). Should catch it
|
||||||
# and report back that the invoice has expired (better robustness)
|
# and report back that the invoice has expired (better robustness)
|
||||||
if response.state == 0: # OPEN
|
if response.state == 0: # OPEN
|
||||||
print("STATUS: OPEN")
|
|
||||||
pass
|
pass
|
||||||
if response.state == 1: # SETTLED
|
if response.state == 1: # SETTLED
|
||||||
pass
|
pass
|
||||||
if response.state == 2: # CANCELLED
|
if response.state == 2: # CANCELLED
|
||||||
pass
|
pass
|
||||||
if response.state == 3: # ACCEPTED (LOCKED)
|
if response.state == 3: # ACCEPTED (LOCKED)
|
||||||
print("STATUS: ACCEPTED")
|
|
||||||
lnpayment.expiry_height = response.htlcs[0].expiry_height
|
lnpayment.expiry_height = response.htlcs[0].expiry_height
|
||||||
lnpayment.status = LNPayment.Status.LOCKED
|
lnpayment.status = LNPayment.Status.LOCKED
|
||||||
lnpayment.save()
|
lnpayment.save()
|
||||||
@ -254,7 +249,6 @@ class LNNode:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
payreq_decoded = cls.decode_payreq(invoice)
|
payreq_decoded = cls.decode_payreq(invoice)
|
||||||
print(payreq_decoded)
|
|
||||||
except:
|
except:
|
||||||
payout["context"] = {
|
payout["context"] = {
|
||||||
"bad_invoice": "Does not look like a valid lightning invoice"
|
"bad_invoice": "Does not look like a valid lightning invoice"
|
||||||
|
@ -725,7 +725,7 @@ class Logics:
|
|||||||
concept=LNPayment.Concepts.PAYBUYER,
|
concept=LNPayment.Concepts.PAYBUYER,
|
||||||
type=LNPayment.Types.NORM,
|
type=LNPayment.Types.NORM,
|
||||||
sender=User.objects.get(username=ESCROW_USERNAME),
|
sender=User.objects.get(username=ESCROW_USERNAME),
|
||||||
order_paid=
|
order_paid_LN=
|
||||||
order, # In case this user has other payouts, update the one related to this order.
|
order, # In case this user has other payouts, update the one related to this order.
|
||||||
receiver=user,
|
receiver=user,
|
||||||
# if there is a LNPayment matching these above, it updates that one with defaults below.
|
# if there is a LNPayment matching these above, it updates that one with defaults below.
|
||||||
|
@ -87,7 +87,7 @@ def follow_send_payment(hash):
|
|||||||
timeout_seconds=timeout_seconds,
|
timeout_seconds=timeout_seconds,
|
||||||
)
|
)
|
||||||
|
|
||||||
order = lnpayment.order_paid
|
order = lnpayment.order_paid_LN
|
||||||
try:
|
try:
|
||||||
for response in LNNode.routerstub.SendPaymentV2(request,
|
for response in LNNode.routerstub.SendPaymentV2(request,
|
||||||
metadata=[
|
metadata=[
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from control.models import AccountingDay, AccountingMonth, BalanceLog
|
from control.models import AccountingDay, BalanceLog
|
||||||
from import_export.admin import ImportExportModelAdmin
|
from import_export.admin import ImportExportModelAdmin
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
@ -17,6 +17,7 @@ class AccountingDayAdmin(ImportExportModelAdmin):
|
|||||||
"inflow",
|
"inflow",
|
||||||
"outflow",
|
"outflow",
|
||||||
"routing_fees",
|
"routing_fees",
|
||||||
|
"mining_fees",
|
||||||
"cashflow",
|
"cashflow",
|
||||||
"outstanding_earned_rewards",
|
"outstanding_earned_rewards",
|
||||||
"outstanding_pending_disputes",
|
"outstanding_pending_disputes",
|
||||||
@ -28,31 +29,6 @@ class AccountingDayAdmin(ImportExportModelAdmin):
|
|||||||
change_links = ["day"]
|
change_links = ["day"]
|
||||||
search_fields = ["day"]
|
search_fields = ["day"]
|
||||||
|
|
||||||
@admin.register(AccountingMonth)
|
|
||||||
class AccountingMonthAdmin(ImportExportModelAdmin):
|
|
||||||
|
|
||||||
list_display = (
|
|
||||||
"month",
|
|
||||||
"contracted",
|
|
||||||
"num_contracts",
|
|
||||||
"net_settled",
|
|
||||||
"net_paid",
|
|
||||||
"net_balance",
|
|
||||||
"inflow",
|
|
||||||
"outflow",
|
|
||||||
"routing_fees",
|
|
||||||
"cashflow",
|
|
||||||
"outstanding_earned_rewards",
|
|
||||||
"outstanding_pending_disputes",
|
|
||||||
"lifetime_rewards_claimed",
|
|
||||||
"outstanding_earned_rewards",
|
|
||||||
"pending_disputes",
|
|
||||||
"rewards_claimed",
|
|
||||||
)
|
|
||||||
change_links = ["month"]
|
|
||||||
search_fields = ["month"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(BalanceLog)
|
@admin.register(BalanceLog)
|
||||||
class BalanceLogAdmin(ImportExportModelAdmin):
|
class BalanceLogAdmin(ImportExportModelAdmin):
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ class AccountingDay(models.Model):
|
|||||||
outflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
outflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
||||||
# Total cost in routing fees
|
# Total cost in routing fees
|
||||||
routing_fees = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
routing_fees = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
||||||
|
# Total cost in minig fees
|
||||||
|
mining_fees = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
||||||
# Total inflows minus outflows and routing fees
|
# Total inflows minus outflows and routing fees
|
||||||
cashflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
cashflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
||||||
# Balance on earned rewards (referral rewards, slashed bonds and solved disputes)
|
# Balance on earned rewards (referral rewards, slashed bonds and solved disputes)
|
||||||
@ -38,41 +40,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):
|
|
||||||
month = models.DateTimeField(primary_key=True, auto_now=False, auto_now_add=False)
|
|
||||||
|
|
||||||
# Every field is denominated in Sats with (3 decimals for millisats)
|
|
||||||
# Total volume contracted
|
|
||||||
contracted = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Number of contracts
|
|
||||||
num_contracts = models.BigIntegerField(default=0, null=False, blank=False)
|
|
||||||
# Net volume of trading invoices settled (excludes disputes)
|
|
||||||
net_settled = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Net volume of trading invoices paid (excludes rewards and disputes)
|
|
||||||
net_paid = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Sum of net settled and net paid
|
|
||||||
net_balance = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Total volume of invoices settled
|
|
||||||
inflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Total volume of invoices paid
|
|
||||||
outflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Total cost in routing fees
|
|
||||||
routing_fees = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Total inflows minus outflows and routing fees
|
|
||||||
cashflow = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Balance on earned rewards (referral rewards, slashed bonds and solved disputes)
|
|
||||||
outstanding_earned_rewards = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Balance on pending disputes (not resolved yet)
|
|
||||||
outstanding_pending_disputes = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Rewards claimed lifetime
|
|
||||||
lifetime_rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Balance change from last day on earned rewards (referral rewards, slashed bonds and solved disputes)
|
|
||||||
earned_rewards = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Balance change on pending disputes (not resolved yet)
|
|
||||||
pending_disputes = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
# Rewards claimed on day
|
|
||||||
rewards_claimed = models.DecimalField(max_digits=15, decimal_places=3, default=0, null=False, blank=False)
|
|
||||||
|
|
||||||
class BalanceLog(models.Model):
|
class BalanceLog(models.Model):
|
||||||
|
|
||||||
def get_total():
|
def get_total():
|
||||||
|
@ -6,7 +6,7 @@ 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 api.models import Order, LNPayment, OnchainPayment, Profile, MarketTick
|
||||||
from control.models import AccountingDay
|
from control.models import AccountingDay
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@ -36,14 +36,16 @@ def do_accounting():
|
|||||||
result = {}
|
result = {}
|
||||||
while day <= today:
|
while day <= today:
|
||||||
day_payments = all_payments.filter(created_at__gte=day,created_at__lte=day+timedelta(days=1))
|
day_payments = all_payments.filter(created_at__gte=day,created_at__lte=day+timedelta(days=1))
|
||||||
|
day_onchain_payments = OnchainPayment.objects.filter(created_at__gte=day,created_at__lte=day+timedelta(days=1))
|
||||||
day_ticks = all_ticks.filter(timestamp__gte=day,timestamp__lte=day+timedelta(days=1))
|
day_ticks = all_ticks.filter(timestamp__gte=day,timestamp__lte=day+timedelta(days=1))
|
||||||
|
|
||||||
# Coarse accounting based on LNpayment objects
|
# Coarse accounting based on LNpayment and OnchainPayment objects
|
||||||
contracted = day_ticks.aggregate(Sum('volume'))['volume__sum']
|
contracted = day_ticks.aggregate(Sum('volume'))['volume__sum']
|
||||||
num_contracts = day_ticks.count()
|
num_contracts = day_ticks.count()
|
||||||
inflow = day_payments.filter(type=LNPayment.Types.HOLD,status=LNPayment.Status.SETLED).aggregate(Sum('num_satoshis'))['num_satoshis__sum']
|
inflow = day_payments.filter(type=LNPayment.Types.HOLD,status=LNPayment.Status.SETLED).aggregate(Sum('num_satoshis'))['num_satoshis__sum']
|
||||||
outflow = day_payments.filter(type=LNPayment.Types.NORM,status=LNPayment.Status.SUCCED).aggregate(Sum('num_satoshis'))['num_satoshis__sum']
|
outflow = day_payments.filter(type=LNPayment.Types.NORM,status=LNPayment.Status.SUCCED).aggregate(Sum('num_satoshis'))['num_satoshis__sum'] + day_onchain_payments.filter(status__in=[OnchainPayment.Status.MEMPO,OnchainPayment.Status.CONFI]).aggregate(Sum('sent_satoshis'))['sent_satoshis__sum']
|
||||||
routing_fees = day_payments.filter(type=LNPayment.Types.NORM,status=LNPayment.Status.SUCCED).aggregate(Sum('fee'))['fee__sum']
|
routing_fees = day_payments.filter(type=LNPayment.Types.NORM,status=LNPayment.Status.SUCCED).aggregate(Sum('fee'))['fee__sum']
|
||||||
|
mining_fees = day_onchain_payments.filter(status__in=[OnchainPayment.Status.MEMPO,OnchainPayment.Status.CONFI]).aggregate(Sum('mining_fee_sats'))['mining_fee_sats__sum']
|
||||||
rewards_claimed = day_payments.filter(type=LNPayment.Types.NORM,concept=LNPayment.Concepts.WITHREWA,status=LNPayment.Status.SUCCED).aggregate(Sum('num_satoshis'))['num_satoshis__sum']
|
rewards_claimed = day_payments.filter(type=LNPayment.Types.NORM,concept=LNPayment.Concepts.WITHREWA,status=LNPayment.Status.SUCCED).aggregate(Sum('num_satoshis'))['num_satoshis__sum']
|
||||||
|
|
||||||
contracted = 0 if contracted == None else contracted
|
contracted = 0 if contracted == None else contracted
|
||||||
@ -59,6 +61,7 @@ def do_accounting():
|
|||||||
inflow = inflow,
|
inflow = inflow,
|
||||||
outflow = outflow,
|
outflow = outflow,
|
||||||
routing_fees = routing_fees,
|
routing_fees = routing_fees,
|
||||||
|
mining_fees = mining_fees,
|
||||||
cashflow = inflow - outflow - routing_fees,
|
cashflow = inflow - outflow - routing_fees,
|
||||||
rewards_claimed = rewards_claimed,
|
rewards_claimed = rewards_claimed,
|
||||||
)
|
)
|
||||||
@ -70,10 +73,21 @@ def do_accounting():
|
|||||||
payouts_paid = 0
|
payouts_paid = 0
|
||||||
routing_cost = 0
|
routing_cost = 0
|
||||||
for payout in payouts:
|
for payout in payouts:
|
||||||
escrows_settled += payout.order_paid.trade_escrow.num_satoshis
|
escrows_settled += payout.order_paid_LN.trade_escrow.num_satoshis
|
||||||
payouts_paid += payout.num_satoshis
|
payouts_paid += payout.num_satoshis
|
||||||
routing_cost += payout.fee
|
routing_cost += payout.fee
|
||||||
|
|
||||||
|
# Same for orders that use onchain payments.
|
||||||
|
payouts_tx = day_onchain_payments.filter(status__in=[OnchainPayment.Status.MEMPO,OnchainPayment.Status.CONFI])
|
||||||
|
escrows_settled = 0
|
||||||
|
payouts_tx_paid = 0
|
||||||
|
mining_cost = 0
|
||||||
|
for payout_tx in payouts_tx:
|
||||||
|
escrows_settled += payout_tx.order_paid_TX.trade_escrow.num_satoshis
|
||||||
|
payouts_tx_paid += payout_tx.sent_satoshis
|
||||||
|
mining_cost += payout_tx.fee
|
||||||
|
|
||||||
|
|
||||||
# account for those orders where bonds were lost
|
# account for those orders where bonds were lost
|
||||||
# + Settled bonds / bond_split
|
# + Settled bonds / bond_split
|
||||||
bonds_settled = day_payments.filter(type=LNPayment.Types.HOLD,concept__in=[LNPayment.Concepts.TAKEBOND,LNPayment.Concepts.MAKEBOND], status=LNPayment.Status.SETLED)
|
bonds_settled = day_payments.filter(type=LNPayment.Types.HOLD,concept__in=[LNPayment.Concepts.TAKEBOND,LNPayment.Concepts.MAKEBOND], status=LNPayment.Status.SETLED)
|
||||||
@ -117,8 +131,8 @@ def compute_node_balance():
|
|||||||
'''
|
'''
|
||||||
Queries LND for channel and wallet balance
|
Queries LND for channel and wallet balance
|
||||||
'''
|
'''
|
||||||
from control.models import BalanceLog
|
|
||||||
|
|
||||||
|
from control.models import BalanceLog
|
||||||
BalanceLog.objects.create()
|
BalanceLog.objects.create()
|
||||||
|
|
||||||
return
|
return
|
@ -936,7 +936,7 @@ class TradeBox extends Component {
|
|||||||
<Grid container spacing={1}>
|
<Grid container spacing={1}>
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
<Typography variant="subtitle1">
|
<Typography variant="subtitle1">
|
||||||
<b>{t("Your invoice looks good!")}</b> {" " + this.stepXofY()}
|
<b>{t("Your info looks good!")}</b> {" " + this.stepXofY()}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} align="center">
|
<Grid item xs={12} align="center">
|
||||||
|
@ -181,6 +181,7 @@
|
|||||||
"You do not have previous orders":"You do not have previous orders",
|
"You do not have previous orders":"You do not have previous orders",
|
||||||
"Join RoboSats' Subreddit":"Join RoboSats' Subreddit",
|
"Join RoboSats' Subreddit":"Join RoboSats' Subreddit",
|
||||||
"RoboSats in Reddit":"RoboSats in Reddit",
|
"RoboSats in Reddit":"RoboSats in Reddit",
|
||||||
|
"Current onchain payout fee":"Current onchain payout fee",
|
||||||
|
|
||||||
"ORDER PAGE - OrderPage.js": "Order details page",
|
"ORDER PAGE - OrderPage.js": "Order details page",
|
||||||
"Order Box":"Order Box",
|
"Order Box":"Order Box",
|
||||||
@ -316,7 +317,7 @@
|
|||||||
"Submit an invoice for {{amountSats}} Sats":"Submit an invoice for {{amountSats}} Sats",
|
"Submit an invoice for {{amountSats}} Sats":"Submit an invoice for {{amountSats}} Sats",
|
||||||
"The taker is committed! Before letting you send {{amountFiat}} {{currencyCode}}, we want to make sure you are able to receive the BTC. Please provide a valid invoice for {{amountSats}} Satoshis.":"The taker is committed! Before letting you send {{amountFiat}} {{currencyCode}}, we want to make sure you are able to receive the BTC. Please provide a valid invoice for {{amountSats}} Satoshis.",
|
"The taker is committed! Before letting you send {{amountFiat}} {{currencyCode}}, we want to make sure you are able to receive the BTC. Please provide a valid invoice for {{amountSats}} Satoshis.":"The taker is committed! Before letting you send {{amountFiat}} {{currencyCode}}, we want to make sure you are able to receive the BTC. Please provide a valid invoice for {{amountSats}} Satoshis.",
|
||||||
"Payout Lightning Invoice":"Payout Lightning Invoice",
|
"Payout Lightning Invoice":"Payout Lightning Invoice",
|
||||||
"Your invoice looks good!":"Your invoice looks good!",
|
"Your info looks good!":"Your info looks good!",
|
||||||
"We are waiting for the seller to lock the trade amount.":"We are waiting for the seller to lock the trade amount.",
|
"We are waiting for the seller to lock the trade amount.":"We are waiting for the seller to lock the trade amount.",
|
||||||
"Just hang on for a moment. If the seller does not deposit, you will get your bond back automatically. In addition, you will receive a compensation (check the rewards in your profile).":"Just hang on for a moment. If the seller does not deposit, you will get your bond back automatically. In addition, you will receive a compensation (check the rewards in your profile).",
|
"Just hang on for a moment. If the seller does not deposit, you will get your bond back automatically. In addition, you will receive a compensation (check the rewards in your profile).":"Just hang on for a moment. If the seller does not deposit, you will get your bond back automatically. In addition, you will receive a compensation (check the rewards in your profile).",
|
||||||
"The trade collateral is locked!":"The trade collateral is locked!",
|
"The trade collateral is locked!":"The trade collateral is locked!",
|
||||||
|
@ -181,6 +181,7 @@
|
|||||||
"You do not have previous orders":"No tienes órdenes previas",
|
"You do not have previous orders":"No tienes órdenes previas",
|
||||||
"Join RoboSats' Subreddit":"Únete al subreddit de RoboSats",
|
"Join RoboSats' Subreddit":"Únete al subreddit de RoboSats",
|
||||||
"RoboSats in Reddit":"RoboSats en Reddit",
|
"RoboSats in Reddit":"RoboSats en Reddit",
|
||||||
|
"Current onchain payout fee":"Coste por envio onchain actual",
|
||||||
|
|
||||||
"ORDER PAGE - OrderPage.js": "Order details page",
|
"ORDER PAGE - OrderPage.js": "Order details page",
|
||||||
"Order Box": "Orden",
|
"Order Box": "Orden",
|
||||||
|
Loading…
Reference in New Issue
Block a user