Coordinator db performance clean up (#561)

* Improve DB writes performance and concurrency. Add order coordinator proceeds field.

* Fix checks on order GET inducing 400
This commit is contained in:
Reckless_Satoshi
2023-05-08 18:10:37 +00:00
committed by Reckless_Satoshi
parent af0289c264
commit 3b77a473f8
13 changed files with 215 additions and 206 deletions

View File

@ -153,10 +153,11 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
else: else:
trade_sats = order.trade_escrow.num_satoshis trade_sats = order.trade_escrow.num_satoshis
order.status = Order.Status.TLD
order.maker.robot.earned_rewards = own_bond_sats + trade_sats order.maker.robot.earned_rewards = own_bond_sats + trade_sats
order.maker.robot.save() order.maker.robot.save(update_fields=["earned_rewards"])
order.save() order.status = Order.Status.TLD
order.save(update_fields=["status"])
self.message_user( self.message_user(
request, request,
f"Dispute of order {order.id} solved successfully on favor of the maker", f"Dispute of order {order.id} solved successfully on favor of the maker",
@ -190,10 +191,12 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
else: else:
trade_sats = order.trade_escrow.num_satoshis trade_sats = order.trade_escrow.num_satoshis
order.status = Order.Status.MLD
order.taker.robot.earned_rewards = own_bond_sats + trade_sats order.taker.robot.earned_rewards = own_bond_sats + trade_sats
order.taker.robot.save() order.taker.robot.save(update_fields=["earned_rewards"])
order.save()
order.status = Order.Status.MLD
order.save(update_fields=["status"])
self.message_user( self.message_user(
request, request,
f"Dispute of order {order.id} solved successfully on favor of the taker", f"Dispute of order {order.id} solved successfully on favor of the taker",
@ -220,17 +223,21 @@ class OrderAdmin(AdminChangeLinksMixin, admin.ModelAdmin):
order.maker_bond.sender.robot.earned_rewards += ( order.maker_bond.sender.robot.earned_rewards += (
order.maker_bond.num_satoshis order.maker_bond.num_satoshis
) )
order.maker_bond.sender.robot.save() order.maker_bond.sender.robot.save(update_fields=["earned_rewards"])
order.taker_bond.sender.robot.earned_rewards += ( order.taker_bond.sender.robot.earned_rewards += (
order.taker_bond.num_satoshis order.taker_bond.num_satoshis
) )
order.taker_bond.sender.robot.save()
order.taker_bond.sender.robot.save(update_fields=["earned_rewards"])
order.trade_escrow.sender.robot.earned_rewards += ( order.trade_escrow.sender.robot.earned_rewards += (
order.trade_escrow.num_satoshis order.trade_escrow.num_satoshis
) )
order.trade_escrow.sender.robot.save() order.trade_escrow.sender.robot.save(update_fields=["earned_rewards"])
order.status = Order.Status.CCA order.status = Order.Status.CCA
order.save() order.save(update_fields=["status"])
self.message_user( self.message_user(
request, request,
f"Dispute of order {order.id} solved successfully, everything returned as compensations", f"Dispute of order {order.id} solved successfully, everything returned as compensations",

View File

@ -164,13 +164,13 @@ class LNNode:
if onchainpayment.status == queue_code: if onchainpayment.status == queue_code:
# Changing the state to "MEMPO" should be atomic with SendCoins. # Changing the state to "MEMPO" should be atomic with SendCoins.
onchainpayment.status = on_mempool_code onchainpayment.status = on_mempool_code
onchainpayment.save() onchainpayment.save(update_fields=["status"])
response = cls.lightningstub.SendCoins(request) response = cls.lightningstub.SendCoins(request)
if response.txid: if response.txid:
onchainpayment.txid = response.txid onchainpayment.txid = response.txid
onchainpayment.broadcasted = True onchainpayment.broadcasted = True
onchainpayment.save() onchainpayment.save(update_fields=["txid", "broadcasted"])
return True return True
elif onchainpayment.status == on_mempool_code: elif onchainpayment.status == on_mempool_code:
@ -253,7 +253,7 @@ class LNNode:
if response.state == 3: # ACCEPTED (LOCKED) if response.state == 3: # ACCEPTED (LOCKED)
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(update_fields=["expiry_height", "status"])
return True return True
@classmethod @classmethod
@ -442,14 +442,14 @@ class LNNode:
failure_reason = cls.payment_failure_context[response.failure_reason] failure_reason = cls.payment_failure_context[response.failure_reason]
lnpayment.failure_reason = response.failure_reason lnpayment.failure_reason = response.failure_reason
lnpayment.status = LNPayment.Status.FAILRO lnpayment.status = LNPayment.Status.FAILRO
lnpayment.save() lnpayment.save(update_fields=["failure_reason", "status"])
return False, failure_reason return False, failure_reason
if response.status == 2: # STATUS 'SUCCEEDED' if response.status == 2: # STATUS 'SUCCEEDED'
lnpayment.status = LNPayment.Status.SUCCED lnpayment.status = LNPayment.Status.SUCCED
lnpayment.fee = float(response.fee_msat) / 1000 lnpayment.fee = float(response.fee_msat) / 1000
lnpayment.preimage = response.payment_preimage lnpayment.preimage = response.payment_preimage
lnpayment.save() lnpayment.save(update_fields=["fee", "status", "preimage"])
return True, None return True, None
return False return False
@ -479,15 +479,15 @@ class LNNode:
def handle_response(response, was_in_transit=False): def handle_response(response, was_in_transit=False):
lnpayment.status = LNPayment.Status.FLIGHT lnpayment.status = LNPayment.Status.FLIGHT
lnpayment.in_flight = True lnpayment.in_flight = True
lnpayment.save() lnpayment.save(update_fields=["in_flight", "status"])
order.status = Order.Status.PAY order.status = Order.Status.PAY
order.save() order.save(update_fields=["status"])
if response.status == 0: # Status 0 'UNKNOWN' if response.status == 0: # Status 0 'UNKNOWN'
# Not sure when this status happens # Not sure when this status happens
print(f"Order: {order.id} UNKNOWN. Hash {hash}") print(f"Order: {order.id} UNKNOWN. Hash {hash}")
lnpayment.in_flight = False lnpayment.in_flight = False
lnpayment.save() lnpayment.save(update_fields=["in_flight"])
if response.status == 1: # Status 1 'IN_FLIGHT' if response.status == 1: # Status 1 'IN_FLIGHT'
print(f"Order: {order.id} IN_FLIGHT. Hash {hash}") print(f"Order: {order.id} IN_FLIGHT. Hash {hash}")
@ -498,7 +498,7 @@ class LNNode:
# 20 minutes in the future so another thread spawns. # 20 minutes in the future so another thread spawns.
if was_in_transit: if was_in_transit:
lnpayment.last_routing_time = timezone.now() + timedelta(minutes=20) lnpayment.last_routing_time = timezone.now() + timedelta(minutes=20)
lnpayment.save() lnpayment.save(update_fields=["last_routing_time"])
if response.status == 3: # Status 3 'FAILED' if response.status == 3: # Status 3 'FAILED'
lnpayment.status = LNPayment.Status.FAILRO lnpayment.status = LNPayment.Status.FAILRO
@ -509,13 +509,21 @@ class LNNode:
if lnpayment.routing_attempts > 2: if lnpayment.routing_attempts > 2:
lnpayment.status = LNPayment.Status.EXPIRE lnpayment.status = LNPayment.Status.EXPIRE
lnpayment.routing_attempts = 0 lnpayment.routing_attempts = 0
lnpayment.save() lnpayment.save(
update_fields=[
"status",
"last_routing_time",
"routing_attempts",
"failure_reason",
"in_flight",
]
)
order.status = Order.Status.FAI order.status = Order.Status.FAI
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.save() order.save(update_fields=["status", "expires_at"])
print( print(
f"Order: {order.id} FAILED. Hash: {hash} Reason: {cls.payment_failure_context[response.failure_reason]}" f"Order: {order.id} FAILED. Hash: {hash} Reason: {cls.payment_failure_context[response.failure_reason]}"
) )
@ -529,12 +537,14 @@ class LNNode:
lnpayment.status = LNPayment.Status.SUCCED lnpayment.status = LNPayment.Status.SUCCED
lnpayment.fee = float(response.fee_msat) / 1000 lnpayment.fee = float(response.fee_msat) / 1000
lnpayment.preimage = response.payment_preimage lnpayment.preimage = response.payment_preimage
lnpayment.save() lnpayment.save(update_fields=["status", "fee", "preimage"])
order.status = Order.Status.SUC order.status = Order.Status.SUC
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.SUC) seconds=order.t_to_expire(Order.Status.SUC)
) )
order.save() order.save(update_fields=["status", "expires_at"])
results = {"succeded": True} results = {"succeded": True}
return results return results
@ -565,12 +575,16 @@ class LNNode:
lnpayment.status = LNPayment.Status.EXPIRE lnpayment.status = LNPayment.Status.EXPIRE
lnpayment.last_routing_time = timezone.now() lnpayment.last_routing_time = timezone.now()
lnpayment.in_flight = False lnpayment.in_flight = False
lnpayment.save() lnpayment.save(
update_fields=["status", "last_routing_time", "in_flight"]
)
order.status = Order.Status.FAI order.status = Order.Status.FAI
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.FAI) seconds=order.t_to_expire(Order.Status.FAI)
) )
order.save() order.save(update_fields=["status", "expires_at"])
results = { results = {
"succeded": False, "succeded": False,
"context": "The payout invoice has expired", "context": "The payout invoice has expired",

View File

@ -1,4 +1,3 @@
import ast
import math import math
from datetime import timedelta from datetime import timedelta
@ -173,7 +172,7 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.TAK) seconds=order.t_to_expire(Order.Status.TAK)
) )
order.save() order.save(update_fields=["amount", "taker", "status", "expires_at"])
return True, None return True, None
def is_buyer(order, user): def is_buyer(order, user):
@ -257,14 +256,14 @@ class Logics:
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.expiry_reason = Order.ExpiryReasons.NMBOND order.expiry_reason = Order.ExpiryReasons.NMBOND
cls.cancel_bond(order.maker_bond) cls.cancel_bond(order.maker_bond)
order.save() order.save(update_fields=["status", "expiry_reason"])
return True return True
elif order.status in [Order.Status.PUB, Order.Status.PAU]: elif order.status in [Order.Status.PUB, Order.Status.PAU]:
cls.return_bond(order.maker_bond) cls.return_bond(order.maker_bond)
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.expiry_reason = Order.ExpiryReasons.NTAKEN order.expiry_reason = Order.ExpiryReasons.NTAKEN
order.save() order.save(update_fields=["status", "expiry_reason"])
send_notification.delay(order_id=order.id, message="order_expired_untaken") send_notification.delay(order_id=order.id, message="order_expired_untaken")
return True return True
@ -284,7 +283,7 @@ class Logics:
cls.cancel_escrow(order) cls.cancel_escrow(order)
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.expiry_reason = Order.ExpiryReasons.NESINV order.expiry_reason = Order.ExpiryReasons.NESINV
order.save() order.save(update_fields=["status", "expiry_reason"])
return True return True
elif order.status == Order.Status.WFE: elif order.status == Order.Status.WFE:
@ -300,9 +299,9 @@ class Logics:
pass pass
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.expiry_reason = Order.ExpiryReasons.NESCRO order.expiry_reason = Order.ExpiryReasons.NESCRO
order.save() order.save(update_fields=["status", "expiry_reason"])
# Reward taker with part of the maker bond # Reward taker with part of the maker bond
cls.add_slashed_rewards(order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
return True return True
# If maker is buyer, settle the taker's bond order goes back to public # If maker is buyer, settle the taker's bond order goes back to public
@ -314,14 +313,10 @@ class Logics:
except Exception: except Exception:
pass pass
taker_bond = order.taker_bond taker_bond = order.taker_bond
order.taker = None
order.taker_bond = None
order.trade_escrow = None
order.payout = None
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_notification.delay(order_id=order.id, message="order_published")
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
return True return True
elif order.status == Order.Status.WFI: elif order.status == Order.Status.WFI:
@ -336,9 +331,9 @@ class Logics:
cls.return_escrow(order) cls.return_escrow(order)
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.expiry_reason = Order.ExpiryReasons.NINVOI order.expiry_reason = Order.ExpiryReasons.NINVOI
order.save() order.save(update_fields=["status", "expiry_reason"])
# Reward taker with part of the maker bond # Reward taker with part of the maker bond
cls.add_slashed_rewards(order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
return True return True
# If maker is seller settle the taker's bond, order goes back to public # If maker is seller settle the taker's bond, order goes back to public
@ -346,13 +341,10 @@ class Logics:
cls.settle_bond(order.taker_bond) cls.settle_bond(order.taker_bond)
cls.return_escrow(order) cls.return_escrow(order)
taker_bond = order.taker_bond taker_bond = order.taker_bond
order.taker = None
order.taker_bond = None
order.trade_escrow = None
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_notification.delay(order_id=order.id, message="order_published")
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
return True return True
elif order.status in [Order.Status.CHA, Order.Status.FSE]: elif order.status in [Order.Status.CHA, Order.Status.FSE]:
@ -371,11 +363,9 @@ class Logics:
robot.penalty_expiration = timezone.now() + timedelta( robot.penalty_expiration = timezone.now() + timedelta(
seconds=PENALTY_TIMEOUT seconds=PENALTY_TIMEOUT
) )
robot.save() robot.save(update_fields=["penalty_expiration"])
# Make order public again # Make order public again
order.taker = None
order.taker_bond = None
cls.publish_order(order) cls.publish_order(order)
return True return True
@ -417,14 +407,14 @@ class Logics:
cls.return_escrow(order) cls.return_escrow(order)
cls.settle_bond(order.maker_bond) cls.settle_bond(order.maker_bond)
cls.return_bond(order.taker_bond) cls.return_bond(order.taker_bond)
cls.add_slashed_rewards(order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
order.status = Order.Status.MLD order.status = Order.Status.MLD
elif num_messages_maker == 0: elif num_messages_maker == 0:
cls.return_escrow(order) cls.return_escrow(order)
cls.settle_bond(order.maker_bond) cls.settle_bond(order.maker_bond)
cls.return_bond(order.taker_bond) cls.return_bond(order.taker_bond)
cls.add_slashed_rewards(order.taker_bond, order.maker_bond) cls.add_slashed_rewards(order, order.taker_bond, order.maker_bond)
order.status = Order.Status.TLD order.status = Order.Status.TLD
else: else:
return False return False
@ -433,7 +423,7 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.DIS) seconds=order.t_to_expire(Order.Status.DIS)
) )
order.save() order.save(update_fields=["status", "is_disputed", "expires_at"])
send_notification.delay(order_id=order.id, message="dispute_opened") send_notification.delay(order_id=order.id, message="dispute_opened")
return True return True
@ -471,7 +461,7 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.DIS) seconds=order.t_to_expire(Order.Status.DIS)
) )
order.save() order.save(update_fields=["is_disputed", "status", "expires_at"])
# User could be None if a dispute is open automatically due to weird expiration. # User could be None if a dispute is open automatically due to weird expiration.
if user is not None: if user is not None:
@ -483,7 +473,7 @@ class Logics:
robot.orders_disputes_started = list( robot.orders_disputes_started = list(
robot.orders_disputes_started robot.orders_disputes_started
).append(str(order.id)) ).append(str(order.id))
robot.save() robot.save(update_fields=["num_disputes", "orders_disputes_started"])
send_notification.delay(order_id=order.id, message="dispute_opened") send_notification.delay(order_id=order.id, message="dispute_opened")
return True, None return True, None
@ -508,8 +498,10 @@ class Logics:
if order.maker == user: if order.maker == user:
order.maker_statement = statement order.maker_statement = statement
order.save(update_fields=["maker_statement"])
else: else:
order.taker_statement = statement order.taker_statement = statement
order.save(update_fields=["taker_statement"])
# If both statements are in, move status to wait for dispute resolution # If both statements are in, move status to wait for dispute resolution
if order.maker_statement not in [None, ""] and order.taker_statement not in [ if order.maker_statement not in [None, ""] and order.taker_statement not in [
@ -520,8 +512,8 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.WFR) seconds=order.t_to_expire(Order.Status.WFR)
) )
order.save(update_fields=["status", "expires_at"])
order.save()
return True, None return True, None
def compute_swap_fee_rate(balance): def compute_swap_fee_rate(balance):
@ -586,20 +578,18 @@ class Logics:
target_conf=config("SUGGESTED_TARGET_CONF", cast=int, default=2), target_conf=config("SUGGESTED_TARGET_CONF", cast=int, default=2),
)["mining_fee_rate"] )["mining_fee_rate"]
# Hardcap mining fee suggested at 300 sats/vbyte # Hardcap mining fee suggested at 1000 sats/vbyte
if suggested_mining_fee_rate > 300: if suggested_mining_fee_rate > 1000:
suggested_mining_fee_rate = 300 suggested_mining_fee_rate = 1000
onchain_payment.suggested_mining_fee_rate = max( onchain_payment.suggested_mining_fee_rate = max(2.05, suggested_mining_fee_rate)
2.05, LNNode.estimate_fee(amount_sats=preliminary_amount)["mining_fee_rate"]
)
onchain_payment.swap_fee_rate = cls.compute_swap_fee_rate( onchain_payment.swap_fee_rate = cls.compute_swap_fee_rate(
onchain_payment.balance onchain_payment.balance
) )
onchain_payment.save() onchain_payment.save()
order.payout_tx = onchain_payment order.payout_tx = onchain_payment
order.save() order.save(update_fields=["payout_tx"])
return True return True
@classmethod @classmethod
@ -747,7 +737,7 @@ class Logics:
tx.save() tx.save()
order.is_swap = True order.is_swap = True
order.save() order.save(update_fields=["is_swap"])
cls.move_state_updated_payout_method(order) cls.move_state_updated_payout_method(order)
@ -817,7 +807,7 @@ class Logics:
) )
order.is_swap = False order.is_swap = False
order.save() order.save(update_fields=["payout", "is_swap"])
cls.move_state_updated_payout_method(order) cls.move_state_updated_payout_method(order)
@ -856,31 +846,11 @@ class Logics:
order.status = Order.Status.PAY order.status = Order.Status.PAY
order.payout.status = LNPayment.Status.FLIGHT order.payout.status = LNPayment.Status.FLIGHT
order.payout.routing_attempts = 0 order.payout.routing_attempts = 0
order.payout.save() order.payout.save(update_fields=["status", "routing_attempts"])
order.save() order.save(update_fields=["status", "expires_at"])
return True return True
def add_robot_rating(robot, rating):
"""adds a new rating to a user robot"""
# TODO Unsafe, does not update ratings, it adds more ratings everytime a new rating is clicked.
robot.total_ratings += 1
latest_ratings = robot.latest_ratings
if latest_ratings is None:
robot.latest_ratings = [rating]
robot.avg_rating = rating
else:
latest_ratings = ast.literal_eval(latest_ratings)
latest_ratings.append(rating)
robot.latest_ratings = latest_ratings
robot.avg_rating = sum(list(map(int, latest_ratings))) / len(
latest_ratings
) # Just an average, but it is a list of strings. Has to be converted to int.
robot.save()
def is_penalized(user): def is_penalized(user):
"""Checks if a user that is not participant of orders """Checks if a user that is not participant of orders
has a limit on taking or making a order""" has a limit on taking or making a order"""
@ -918,7 +888,7 @@ class Logics:
if order.status == Order.Status.WFB and order.maker == user: if order.status == Order.Status.WFB and order.maker == user:
cls.cancel_bond(order.maker_bond) cls.cancel_bond(order.maker_bond)
order.status = Order.Status.UCA order.status = Order.Status.UCA
order.save() order.save(update_fields=["status"])
return True, None return True, None
# 2.a) When maker cancels after bond # 2.a) When maker cancels after bond
@ -932,7 +902,7 @@ class Logics:
# Return the maker bond (Maker gets returned the bond for cancelling public order) # Return the maker bond (Maker gets returned the bond for cancelling public order)
if cls.return_bond(order.maker_bond): if cls.return_bond(order.maker_bond):
order.status = Order.Status.UCA order.status = Order.Status.UCA
order.save() order.save(update_fields=["status"])
send_notification.delay( send_notification.delay(
order_id=order.id, message="public_order_cancelled" order_id=order.id, message="public_order_cancelled"
) )
@ -947,7 +917,7 @@ class Logics:
if cls.return_bond(order.maker_bond): if cls.return_bond(order.maker_bond):
cls.cancel_bond(order.taker_bond) cls.cancel_bond(order.taker_bond)
order.status = Order.Status.UCA order.status = Order.Status.UCA
order.save() order.save(update_fields=["status"])
send_notification.delay( send_notification.delay(
order_id=order.id, message="public_order_cancelled" order_id=order.id, message="public_order_cancelled"
) )
@ -981,9 +951,9 @@ class Logics:
if valid: if valid:
order.status = Order.Status.UCA order.status = Order.Status.UCA
order.save() order.save(update_fields=["status"])
# Reward taker with part of the maker bond # Reward taker with part of the maker bond
cls.add_slashed_rewards(order.maker_bond, order.taker_bond) cls.add_slashed_rewards(order, order.maker_bond, order.taker_bond)
return True, None return True, None
# 4.b) When taker cancel after bond (before escrow) # 4.b) When taker cancel after bond (before escrow)
@ -996,13 +966,11 @@ class Logics:
# Settle the maker bond (Maker loses the bond for canceling an ongoing trade) # Settle the maker bond (Maker loses the bond for canceling an ongoing trade)
valid = cls.settle_bond(order.taker_bond) valid = cls.settle_bond(order.taker_bond)
if valid: if valid:
order.taker = None taker_bond = order.taker_bond
order.payout = None
order.trade_escrow = None
cls.publish_order(order) cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published") send_notification.delay(order_id=order.id, message="order_published")
# Reward maker with part of the taker bond # Reward maker with part of the taker bond
cls.add_slashed_rewards(order.taker_bond, order.maker_bond) cls.add_slashed_rewards(order, taker_bond, order.maker_bond)
return True, None return True, None
# 5) When trade collateral has been posted (after escrow) # 5) When trade collateral has been posted (after escrow)
@ -1026,12 +994,12 @@ class Logics:
# Otherwise just make true the asked for cancel flags # Otherwise just make true the asked for cancel flags
elif user == order.taker: elif user == order.taker:
order.taker_asked_cancel = True order.taker_asked_cancel = True
order.save() order.save(update_fields=["taker_asked_cancel"])
return True, None return True, None
elif user == order.maker: elif user == order.maker:
order.maker_asked_cancel = True order.maker_asked_cancel = True
order.save() order.save(update_fields=["maker_asked_cancel"])
return True, None return True, None
else: else:
@ -1047,7 +1015,7 @@ class Logics:
cls.return_bond(order.taker_bond) cls.return_bond(order.taker_bond)
cls.return_escrow(order) cls.return_escrow(order)
order.status = Order.Status.CCA order.status = Order.Status.CCA
order.save() order.save(update_fields=["status"])
send_notification.delay(order_id=order.id, message="collaborative_cancelled") send_notification.delay(order_id=order.id, message="collaborative_cancelled")
return return
@ -1061,7 +1029,16 @@ class Logics:
order.amount = None order.amount = None
order.last_satoshis = cls.satoshis_now(order) order.last_satoshis = cls.satoshis_now(order)
order.last_satoshis_time = timezone.now() order.last_satoshis_time = timezone.now()
order.save()
# clear fields in case of re-publishing after expiry
order.taker = None
order.taker_bond = None
order.trade_escrow = None
order.payout = None
order.payout_tx = None
order.save() # update all fields
# send_notification.delay(order_id=order.id,'order_published') # too spammy # send_notification.delay(order_id=order.id,'order_published') # too spammy
return return
@ -1087,16 +1064,6 @@ class Logics:
return cltv_expiry_blocks return cltv_expiry_blocks
@classmethod
def is_maker_bond_locked(cls, order):
if order.maker_bond.status == LNPayment.Status.LOCKED:
return True
elif LNNode.validate_hold_invoice_locked(order.maker_bond):
cls.publish_order(order)
send_notification.delay(order_id=order.id, message="order_published")
return True
return False
@classmethod @classmethod
def gen_maker_hold_invoice(cls, order, user): def gen_maker_hold_invoice(cls, order, user):
@ -1109,9 +1076,6 @@ class Logics:
# Return the previous invoice if there was one and is still unpaid # Return the previous invoice if there was one and is still unpaid
if order.maker_bond: if order.maker_bond:
if cls.is_maker_bond_locked(order):
return False, None
elif order.maker_bond.status == LNPayment.Status.INVGEN:
return True, { return True, {
"bond_invoice": order.maker_bond.invoice, "bond_invoice": order.maker_bond.invoice,
"bond_satoshis": order.maker_bond.num_satoshis, "bond_satoshis": order.maker_bond.num_satoshis,
@ -1162,7 +1126,7 @@ class Logics:
cltv_expiry=hold_payment["cltv_expiry"], cltv_expiry=hold_payment["cltv_expiry"],
) )
order.save() order.save(update_fields=["last_satoshis", "last_satoshis_time", "maker_bond"])
return True, { return True, {
"bond_invoice": hold_payment["invoice"], "bond_invoice": hold_payment["invoice"],
"bond_satoshis": bond_satoshis, "bond_satoshis": bond_satoshis,
@ -1178,20 +1142,27 @@ class Logics:
order.last_satoshis = cls.satoshis_now(order) order.last_satoshis = cls.satoshis_now(order)
order.last_satoshis_time = timezone.now() order.last_satoshis_time = timezone.now()
order.taker_bond.status = LNPayment.Status.LOCKED order.taker_bond.status = LNPayment.Status.LOCKED
order.taker_bond.save() order.taker_bond.save(update_fields=["status"])
# With the bond confirmation the order is extended 'public_order_duration' hours # With the bond confirmation the order is extended 'public_order_duration' hours
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.WF2) seconds=order.t_to_expire(Order.Status.WF2)
) )
order.status = Order.Status.WF2 order.status = Order.Status.WF2
order.save() order.save(
update_fields=[
"last_satoshis",
"last_satoshis_time",
"expires_at",
"status",
]
)
# Both users robots are added one more contract // Unsafe can add more than once. # Both users robots are added one more contract // Unsafe can add more than once.
order.maker.robot.total_contracts += 1 order.maker.robot.total_contracts += 1
order.taker.robot.total_contracts += 1 order.taker.robot.total_contracts += 1
order.maker.robot.save() order.maker.robot.save(update_fields=["total_contracts"])
order.taker.robot.save() order.taker.robot.save(update_fields=["total_contracts"])
# Log a market tick # Log a market tick
try: try:
@ -1201,15 +1172,6 @@ class Logics:
send_notification.delay(order_id=order.id, message="order_taken_confirmed") send_notification.delay(order_id=order.id, message="order_taken_confirmed")
return True return True
@classmethod
def is_taker_bond_locked(cls, order):
if order.taker_bond.status == LNPayment.Status.LOCKED:
return True
elif LNNode.validate_hold_invoice_locked(order.taker_bond):
cls.finalize_contract(order)
return True
return False
@classmethod @classmethod
def gen_taker_hold_invoice(cls, order, user): def gen_taker_hold_invoice(cls, order, user):
@ -1222,9 +1184,6 @@ class Logics:
# Do not gen if a taker invoice exist. Do not return if it is already locked. Return the old one if still waiting. # Do not gen if a taker invoice exist. Do not return if it is already locked. Return the old one if still waiting.
if order.taker_bond: if order.taker_bond:
if cls.is_taker_bond_locked(order):
return False, None
elif order.taker_bond.status == LNPayment.Status.INVGEN:
return True, { return True, {
"bond_invoice": order.taker_bond.invoice, "bond_invoice": order.taker_bond.invoice,
"bond_satoshis": order.taker_bond.num_satoshis, "bond_satoshis": order.taker_bond.num_satoshis,
@ -1277,7 +1236,14 @@ class Logics:
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.TAK) seconds=order.t_to_expire(Order.Status.TAK)
) )
order.save() order.save(
update_fields=[
"expires_at",
"last_satoshis_time",
"taker_bond",
"expires_at",
]
)
return True, { return True, {
"bond_invoice": hold_payment["invoice"], "bond_invoice": hold_payment["invoice"],
"bond_satoshis": bond_satoshis, "bond_satoshis": bond_satoshis,
@ -1288,24 +1254,15 @@ class Logics:
# If status is 'Waiting for both' move to Waiting for invoice # If status is 'Waiting for both' move to Waiting for invoice
if order.status == Order.Status.WF2: if order.status == Order.Status.WF2:
order.status = Order.Status.WFI order.status = Order.Status.WFI
order.save(update_fields=["status"])
# If status is 'Waiting for invoice' move to Chat # If status is 'Waiting for invoice' move to Chat
elif order.status == Order.Status.WFE: elif order.status == Order.Status.WFE:
order.status = Order.Status.CHA order.status = Order.Status.CHA
order.expires_at = timezone.now() + timedelta( order.expires_at = timezone.now() + timedelta(
seconds=order.t_to_expire(Order.Status.CHA) seconds=order.t_to_expire(Order.Status.CHA)
) )
order.save(update_fields=["status", "expires_at"])
send_notification.delay(order_id=order.id, message="fiat_exchange_starts") send_notification.delay(order_id=order.id, message="fiat_exchange_starts")
order.save()
@classmethod
def is_trade_escrow_locked(cls, order):
if order.trade_escrow.status == LNPayment.Status.LOCKED:
cls.trade_escrow_received(order)
return True
elif LNNode.validate_hold_invoice_locked(order.trade_escrow):
cls.trade_escrow_received(order)
return True
return False
@classmethod @classmethod
def gen_escrow_hold_invoice(cls, order, user): def gen_escrow_hold_invoice(cls, order, user):
@ -1319,10 +1276,6 @@ class Logics:
# Do not gen if an escrow invoice exist. Do not return if it is already locked. Return the old one if still waiting. # Do not gen if an escrow invoice exist. Do not return if it is already locked. Return the old one if still waiting.
if order.trade_escrow: if order.trade_escrow:
# Check if status is INVGEN and still not expired
if cls.is_trade_escrow_locked(order):
return False, None
elif order.trade_escrow.status == LNPayment.Status.INVGEN:
return True, { return True, {
"escrow_invoice": order.trade_escrow.invoice, "escrow_invoice": order.trade_escrow.invoice,
"escrow_satoshis": order.trade_escrow.num_satoshis, "escrow_satoshis": order.trade_escrow.num_satoshis,
@ -1370,7 +1323,7 @@ class Logics:
cltv_expiry=hold_payment["cltv_expiry"], cltv_expiry=hold_payment["cltv_expiry"],
) )
order.save() order.save(update_fields=["trade_escrow"])
return True, { return True, {
"escrow_invoice": hold_payment["invoice"], "escrow_invoice": hold_payment["invoice"],
"escrow_satoshis": escrow_satoshis, "escrow_satoshis": escrow_satoshis,
@ -1380,21 +1333,21 @@ class Logics:
"""Settles the trade escrow hold invoice""" """Settles the trade escrow hold invoice"""
if LNNode.settle_hold_invoice(order.trade_escrow.preimage): if LNNode.settle_hold_invoice(order.trade_escrow.preimage):
order.trade_escrow.status = LNPayment.Status.SETLED order.trade_escrow.status = LNPayment.Status.SETLED
order.trade_escrow.save() order.trade_escrow.save(update_fields=["status"])
return True return True
def settle_bond(bond): def settle_bond(bond):
"""Settles the bond hold invoice""" """Settles the bond hold invoice"""
if LNNode.settle_hold_invoice(bond.preimage): if LNNode.settle_hold_invoice(bond.preimage):
bond.status = LNPayment.Status.SETLED bond.status = LNPayment.Status.SETLED
bond.save() bond.save(update_fields=["status"])
return True return True
def return_escrow(order): def return_escrow(order):
"""returns the trade escrow""" """returns the trade escrow"""
if LNNode.cancel_return_hold_invoice(order.trade_escrow.payment_hash): if LNNode.cancel_return_hold_invoice(order.trade_escrow.payment_hash):
order.trade_escrow.status = LNPayment.Status.RETNED order.trade_escrow.status = LNPayment.Status.RETNED
order.trade_escrow.save() order.trade_escrow.save(update_fields=["status"])
return True return True
def cancel_escrow(order): def cancel_escrow(order):
@ -1402,7 +1355,7 @@ class Logics:
# Same as return escrow, but used when the invoice was never LOCKED # Same as return escrow, but used when the invoice was never LOCKED
if LNNode.cancel_return_hold_invoice(order.trade_escrow.payment_hash): if LNNode.cancel_return_hold_invoice(order.trade_escrow.payment_hash):
order.trade_escrow.status = LNPayment.Status.CANCEL order.trade_escrow.status = LNPayment.Status.CANCEL
order.trade_escrow.save() order.trade_escrow.save(update_fields=["status"])
return True return True
def return_bond(bond): def return_bond(bond):
@ -1412,12 +1365,12 @@ class Logics:
try: try:
LNNode.cancel_return_hold_invoice(bond.payment_hash) LNNode.cancel_return_hold_invoice(bond.payment_hash)
bond.status = LNPayment.Status.RETNED bond.status = LNPayment.Status.RETNED
bond.save() bond.save(update_fields=["status"])
return True return True
except Exception as e: except Exception as e:
if "invoice already settled" in str(e): if "invoice already settled" in str(e):
bond.status = LNPayment.Status.SETLED bond.status = LNPayment.Status.SETLED
bond.save() bond.save(update_fields=["status"])
return True return True
else: else:
raise e raise e
@ -1427,7 +1380,7 @@ class Logics:
if order.payout_tx: if order.payout_tx:
order.payout_tx.status = OnchainPayment.Status.CANCE order.payout_tx.status = OnchainPayment.Status.CANCE
order.payout_tx.save() order.payout_tx.save(update_fields=["status"])
return True return True
else: else:
return False return False
@ -1440,12 +1393,12 @@ class Logics:
try: try:
LNNode.cancel_return_hold_invoice(bond.payment_hash) LNNode.cancel_return_hold_invoice(bond.payment_hash)
bond.status = LNPayment.Status.CANCEL bond.status = LNPayment.Status.CANCEL
bond.save() bond.save(update_fields=["status"])
return True return True
except Exception as e: except Exception as e:
if "invoice already settled" in str(e): if "invoice already settled" in str(e):
bond.status = LNPayment.Status.SETLED bond.status = LNPayment.Status.SETLED
bond.save() bond.save(update_fields=["status"])
return True return True
else: else:
raise e raise e
@ -1457,13 +1410,14 @@ class Logics:
# Pay to buyer invoice # Pay to buyer invoice
if not order.is_swap: if not order.is_swap:
# Background process "follow_invoices" will try to pay this invoice until success # Background process "follow_invoices" will try to pay this invoice until success
order.status = Order.Status.PAY
order.payout.status = LNPayment.Status.FLIGHT order.payout.status = LNPayment.Status.FLIGHT
order.payout.save() order.payout.save(update_fields=["status"])
order.save()
send_notification.delay(order_id=order.id, message="trade_successful") order.status = Order.Status.PAY
order.contract_finalization_time = timezone.now() order.contract_finalization_time = timezone.now()
order.save() order.save(update_fields=["status", "contract_finalization_time"])
send_notification.delay(order_id=order.id, message="trade_successful")
return True return True
# Pay onchain to address # Pay onchain to address
@ -1472,13 +1426,14 @@ class Logics:
return False return False
else: else:
# Add onchain payment to queue # Add onchain payment to queue
order.status = Order.Status.SUC
order.payout_tx.status = OnchainPayment.Status.QUEUE order.payout_tx.status = OnchainPayment.Status.QUEUE
order.payout_tx.save() order.payout_tx.save(update_fields=["status"])
order.save()
send_notification.delay(order_id=order.id, message="trade_successful") order.status = Order.Status.SUC
order.contract_finalization_time = timezone.now() order.contract_finalization_time = timezone.now()
order.save() order.save(update_fields=["status", "contract_finalization_time"])
send_notification.delay(order_id=order.id, message="trade_successful")
return True return True
@classmethod @classmethod
@ -1493,6 +1448,7 @@ class Logics:
if cls.is_buyer(order, user): if cls.is_buyer(order, user):
order.status = Order.Status.FSE order.status = Order.Status.FSE
order.is_fiat_sent = True order.is_fiat_sent = True
order.save(update_fields=["status", "is_fiat_sent"])
# If seller and fiat was sent, SETTLE ESCROW AND PAY BUYER INVOICE # If seller and fiat was sent, SETTLE ESCROW AND PAY BUYER INVOICE
elif cls.is_seller(order, user): elif cls.is_seller(order, user):
@ -1515,6 +1471,7 @@ class Logics:
# !!! KEY LINE - SETTLES THE TRADE ESCROW !!! # !!! KEY LINE - SETTLES THE TRADE ESCROW !!!
if cls.settle_escrow(order): if cls.settle_escrow(order):
order.trade_escrow.status = LNPayment.Status.SETLED order.trade_escrow.status = LNPayment.Status.SETLED
order.trade_escrow.save(update_fields=["status"])
# Double check the escrow is settled. # Double check the escrow is settled.
if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash): if LNNode.double_check_htlc_is_settled(order.trade_escrow.payment_hash):
@ -1524,6 +1481,9 @@ class Logics:
# !!! KEY LINE - PAYS THE BUYER INVOICE !!! # !!! KEY LINE - PAYS THE BUYER INVOICE !!!
cls.pay_buyer(order) cls.pay_buyer(order)
# Computes coordinator trade revenue
cls.compute_proceeds(order)
return True, None return True, None
else: else:
@ -1531,7 +1491,6 @@ class Logics:
"bad_request": "You cannot confirm the fiat payment at this stage" "bad_request": "You cannot confirm the fiat payment at this stage"
} }
order.save()
return True, None return True, None
@classmethod @classmethod
@ -1551,7 +1510,7 @@ class Logics:
order.status = Order.Status.CHA order.status = Order.Status.CHA
order.is_fiat_sent = False order.is_fiat_sent = False
order.reverted_fiat_sent = True order.reverted_fiat_sent = True
order.save() order.save(update_fields=["status", "is_fiat_sent", "reverted_fiat_sent"])
return True, None return True, None
@ -1569,17 +1528,18 @@ class Logics:
return False, { return False, {
"bad_request": "You can only pause/unpause an order that is either public or paused" "bad_request": "You can only pause/unpause an order that is either public or paused"
} }
order.save() order.save(update_fields=["status"])
return True, None return True, None
@classmethod @classmethod
def rate_platform(cls, user, rating): def rate_platform(cls, user, rating):
user.robot.platform_rating = rating user.robot.platform_rating = rating
user.robot.save() user.robot.save(update_fields=["platform_rating"])
return True, None return True, None
@classmethod @classmethod
def add_slashed_rewards(cls, slashed_bond, staked_bond): def add_slashed_rewards(cls, order, slashed_bond, staked_bond):
""" """
When a bond is slashed due to overtime, rewards the user that was waiting. When a bond is slashed due to overtime, rewards the user that was waiting.
@ -1603,12 +1563,16 @@ class Logics:
reward = int(slashed_satoshis * reward_fraction) reward = int(slashed_satoshis * reward_fraction)
rewarded_robot = staked_bond.sender.robot rewarded_robot = staked_bond.sender.robot
rewarded_robot.earned_rewards += reward rewarded_robot.earned_rewards += reward
rewarded_robot.save() rewarded_robot.save(update_fields=["earned_rewards"])
if slashed_return > 100: if slashed_return > 100:
slashed_robot = slashed_bond.sender.robot slashed_robot = slashed_bond.sender.robot
slashed_robot.earned_rewards += slashed_return slashed_robot.earned_rewards += slashed_return
slashed_robot.save() slashed_robot.save(update_fields=["earned_rewards"])
proceeds = int(slashed_satoshis * (1 - reward_fraction))
order.proceeds += proceeds
order.save(update_fields=["proceeds"])
return return
@ -1656,24 +1620,39 @@ class Logics:
return False, {"bad_invoice": "Give me a new invoice"} return False, {"bad_invoice": "Give me a new invoice"}
user.robot.earned_rewards = 0 user.robot.earned_rewards = 0
user.robot.save() user.robot.save(update_fields=["earned_rewards"])
# Pays the invoice. # Pays the invoice.
paid, failure_reason = LNNode.pay_invoice(lnpayment) paid, failure_reason = LNNode.pay_invoice(lnpayment)
if paid: if paid:
user.robot.earned_rewards = 0 user.robot.earned_rewards = 0
user.robot.claimed_rewards += num_satoshis user.robot.claimed_rewards += num_satoshis
user.robot.save() user.robot.save(update_fields=["earned_rewards", "claimed_rewards"])
return True, None return True, None
# If fails, adds the rewards again. # If fails, adds the rewards again.
else: else:
user.robot.earned_rewards = num_satoshis user.robot.earned_rewards = num_satoshis
user.robot.save() user.robot.save(update_fields=["earned_rewards"])
context = {} context = {}
context["bad_invoice"] = failure_reason context["bad_invoice"] = failure_reason
return False, context return False, context
@classmethod
def compute_proceeds(cls, order):
"""
Computes Coordinator trade proceeds for finished orders.
"""
if order.is_swap:
payout_sats = order.payout_tx.sent_satoshis + order.payout_tx.mining_fee
order.proceeds += int(order.trade_escrow.num_satoshis - payout_sats)
else:
payout_sats = order.payout.num_satoshis + order.payout.fee
order.proceeds += int(order.trade_escrow.num_satoshis - payout_sats)
order.save(update_fields=["proceeds"])
@classmethod @classmethod
def summarize_trade(cls, order, user): def summarize_trade(cls, order, user):
""" """
@ -1750,7 +1729,7 @@ class Logics:
platform_summary["contract_timestamp"] = order.last_satoshis_time platform_summary["contract_timestamp"] = order.last_satoshis_time
if order.contract_finalization_time is None: if order.contract_finalization_time is None:
order.contract_finalization_time = timezone.now() order.contract_finalization_time = timezone.now()
order.save() order.save(update_fields=["contract_finalization_time"])
platform_summary["contract_total_time"] = ( platform_summary["contract_total_time"] = (
order.contract_finalization_time - order.last_satoshis_time order.contract_finalization_time - order.last_satoshis_time
) )

View File

@ -17,8 +17,6 @@ class Command(BaseCommand):
"""Continuously checks order expiration times for 1 hour. If order """Continuously checks order expiration times for 1 hour. If order
has expires, it calls the logics module for expiration handling.""" has expires, it calls the logics module for expiration handling."""
# TODO handle 'database is locked'
do_nothing = [ do_nothing = [
Order.Status.UCA, Order.Status.UCA,
Order.Status.EXP, Order.Status.EXP,
@ -61,7 +59,7 @@ class Command(BaseCommand):
if "unable to locate invoice" in str(e): if "unable to locate invoice" in str(e):
self.stdout.write(str(e)) self.stdout.write(str(e))
order.status = Order.Status.EXP order.status = Order.Status.EXP
order.save() order.save(update_fields=["status"])
debug["expired_orders"].append({idx: context}) debug["expired_orders"].append({idx: context})
if debug["num_expired_orders"] > 0: if debug["num_expired_orders"] > 0:
@ -69,7 +67,8 @@ class Command(BaseCommand):
self.stdout.write(str(debug)) self.stdout.write(str(debug))
def handle(self, *args, **options): def handle(self, *args, **options):
"""Never mind database locked error, keep going, print them out""" """Never mind database locked error, keep going, print them out.
Not an issue with PostgresQL"""
try: try:
self.clean_orders() self.clean_orders()
except Exception as e: except Exception as e:

View File

@ -70,7 +70,7 @@ class Command(BaseCommand):
# self.handle_status_change(hold_lnpayment, old_status) # self.handle_status_change(hold_lnpayment, old_status)
hold_lnpayment.status = new_status hold_lnpayment.status = new_status
self.update_order_status(hold_lnpayment) self.update_order_status(hold_lnpayment)
hold_lnpayment.save() hold_lnpayment.save(update_fields=["status"])
# Report for debugging # Report for debugging
old = LNPayment.Status(old_status).label old = LNPayment.Status(old_status).label
@ -174,7 +174,6 @@ class Command(BaseCommand):
OnchainPayment.Status.QUEUE, OnchainPayment.Status.QUEUE,
OnchainPayment.Status.MEMPO, OnchainPayment.Status.MEMPO,
) )
onchainpayment.save()
else: else:
self.stderr.write( self.stderr.write(
@ -215,9 +214,9 @@ class Command(BaseCommand):
self.stderr.write( self.stderr.write(
f"Weird! bond with hash {lnpayment.payment_hash} was locked, yet it is not related to any order. It will be instantly cancelled." f"Weird! bond with hash {lnpayment.payment_hash} was locked, yet it is not related to any order. It will be instantly cancelled."
) )
LNNode.cancel_return_hold_invoice(lnpayment.payment_hash) if LNNode.cancel_return_hold_invoice(lnpayment.payment_hash):
lnpayment.status = LNPayment.Status.RETNED lnpayment.status = LNPayment.Status.RETNED
lnpayment.save() lnpayment.save(update_fields=["status"])
return return
except Exception as e: except Exception as e:

View File

@ -74,7 +74,13 @@ class Command(BaseCommand):
] ]
self.telegram.welcome(robot.user) self.telegram.welcome(robot.user)
robot.telegram_enabled = True robot.telegram_enabled = True
robot.save() robot.save(
update_fields=[
"telegram_lang_code",
"telegram_chat_id",
"telegram_enabled",
]
)
break break
except Exception: except Exception:
time.sleep(5) time.sleep(5)

View File

@ -70,12 +70,10 @@ class MarketTick(models.Model):
market_exchange_rate = float(order.currency.exchange_rate) market_exchange_rate = float(order.currency.exchange_rate)
premium = 100 * (price / market_exchange_rate - 1) premium = 100 * (price / market_exchange_rate - 1)
tick = MarketTick.objects.create( MarketTick.objects.create(
price=price, volume=volume, premium=premium, currency=order.currency price=price, volume=volume, premium=premium, currency=order.currency
) )
tick.save()
def __str__(self): def __str__(self):
return f"Tick: {str(self.id)[:8]}" return f"Tick: {str(self.id)[:8]}"

View File

@ -221,6 +221,14 @@ class Order(models.Model):
blank=True, blank=True,
) )
# coordinator proceeds (sats revenue for this order)
proceeds = models.PositiveBigIntegerField(
default=0,
null=True,
validators=[MinValueValidator(0)],
blank=True,
)
# ratings # ratings
maker_rated = models.BooleanField(default=False, null=False) maker_rated = models.BooleanField(default=False, null=False)
taker_rated = models.BooleanField(default=False, null=False) taker_rated = models.BooleanField(default=False, null=False)

View File

@ -22,7 +22,7 @@ class Telegram:
if user.robot.telegram_token is None: if user.robot.telegram_token is None:
user.robot.telegram_token = token_urlsafe(15) user.robot.telegram_token = token_urlsafe(15)
user.robot.save() user.robot.save(update_fields=["telegram_token"])
context["tg_token"] = user.robot.telegram_token context["tg_token"] = user.robot.telegram_token
context["tg_bot_name"] = config("TELEGRAM_BOT_NAME") context["tg_bot_name"] = config("TELEGRAM_BOT_NAME")
@ -54,7 +54,7 @@ class Telegram:
text = f"🔔 Hey {user.username}, I will send you notifications about your RoboSats orders." text = f"🔔 Hey {user.username}, I will send you notifications about your RoboSats orders."
self.send_message(user.robot.telegram_chat_id, text) self.send_message(user.robot.telegram_chat_id, text)
user.robot.telegram_welcomed = True user.robot.telegram_welcomed = True
user.robot.save() user.robot.save(update_fields=["telegram_welcomed"])
return return
def order_taken_confirmed(self, order): def order_taken_confirmed(self, order):

View File

@ -61,7 +61,7 @@ def follow_send_payment(hash):
lnpayment = LNPayment.objects.get(payment_hash=hash) lnpayment = LNPayment.objects.get(payment_hash=hash)
lnpayment.last_routing_time = timezone.now() lnpayment.last_routing_time = timezone.now()
lnpayment.save() lnpayment.save(update_fields=["last_routing_time"])
# Default is 0ppm. Set by the user over API. Client's default is 1000 ppm. # Default is 0ppm. Set by the user over API. Client's default is 1000 ppm.
fee_limit_sat = int( fee_limit_sat = int(

View File

@ -1102,6 +1102,6 @@ class StealthView(APIView):
stealth = serializer.data.get("wantsStealth") stealth = serializer.data.get("wantsStealth")
request.user.robot.wants_stealth = stealth request.user.robot.wants_stealth = stealth
request.user.robot.save() request.user.robot.save(update_fields=["wants_stealth"])
return Response({"wantsStealth": stealth}) return Response({"wantsStealth": stealth})

View File

@ -76,7 +76,6 @@ class ChatView(viewsets.ViewSet):
timezone.now() - timedelta(minutes=1) timezone.now() - timedelta(minutes=1)
) )
chatroom.maker_connected = True chatroom.maker_connected = True
chatroom.save()
peer_connected = chatroom.taker_connected peer_connected = chatroom.taker_connected
peer_public_key = order.taker.robot.public_key peer_public_key = order.taker.robot.public_key
elif chatroom.taker == request.user: elif chatroom.taker == request.user:
@ -84,10 +83,11 @@ class ChatView(viewsets.ViewSet):
timezone.now() - timedelta(minutes=1) timezone.now() - timedelta(minutes=1)
) )
chatroom.taker_connected = True chatroom.taker_connected = True
chatroom.save()
peer_connected = chatroom.maker_connected peer_connected = chatroom.maker_connected
peer_public_key = order.maker.robot.public_key peer_public_key = order.maker.robot.public_key
chatroom.save(update_fields=["maker_connected", "taker_connected"])
messages = [] messages = []
for message in queryset: for message in queryset:
d = ChatSerializer(message).data d = ChatSerializer(message).data

View File

@ -297,8 +297,7 @@ export const useAppStore = () => {
if (currentOrder) { if (currentOrder) {
apiClient apiClient
.get(baseUrl, '/api/order/?order_id=' + currentOrder, { tokenSHA256: robot.tokenSHA256 }) .get(baseUrl, '/api/order/?order_id=' + currentOrder, { tokenSHA256: robot.tokenSHA256 })
.then(orderReceived) .then(orderReceived);
.catch(orderReceived);
} }
}; };