From cbb063f06d908b30fda110a29c6ee03ce60e1a94 Mon Sep 17 00:00:00 2001 From: koalasat Date: Mon, 15 Jul 2024 12:33:09 +0200 Subject: [PATCH] NIP corrections --- api/logics.py | 49 ++++++++++++++++++++++++++++++++++---------- api/nostr.py | 21 +++++++++++++++---- api/tasks.py | 5 ++--- docker-tests.yml | 16 +++++++-------- requirements.txt | 1 + tests/utils/trade.py | 4 ++-- 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/api/logics.py b/api/logics.py index da562bc4..8bec242a 100644 --- a/api/logics.py +++ b/api/logics.py @@ -8,7 +8,7 @@ from django.utils import timezone from api.lightning.node import LNNode from api.models import Currency, LNPayment, MarketTick, OnchainPayment, Order -from api.tasks import send_devfund_donation, send_notification, send_order_nostr_event +from api.tasks import send_devfund_donation, send_notification, nostr_send_order_event from api.utils import get_minning_fee, validate_onchain_address, location_country from chat.models import Message @@ -704,9 +704,9 @@ class Logics: if context["invoice_amount"] < MIN_SWAP_AMOUNT: context["swap_allowed"] = False - context[ - "swap_failure_reason" - ] = f"Order amount is smaller than the minimum swap available of {MIN_SWAP_AMOUNT} Sats" + context["swap_failure_reason"] = ( + f"Order amount is smaller than the minimum swap available of {MIN_SWAP_AMOUNT} Sats" + ) order.log( f"Onchain payment option was not offered: amount is smaller than the minimum swap available of {MIN_SWAP_AMOUNT} Sats", level="WARN", @@ -714,9 +714,9 @@ class Logics: return True, context elif context["invoice_amount"] > MAX_SWAP_AMOUNT: context["swap_allowed"] = False - context[ - "swap_failure_reason" - ] = f"Order amount is bigger than the maximum swap available of {MAX_SWAP_AMOUNT} Sats" + context["swap_failure_reason"] = ( + f"Order amount is bigger than the maximum swap available of {MAX_SWAP_AMOUNT} Sats" + ) order.log( f"Onchain payment option was not offered: amount is bigger than the maximum swap available of {MAX_SWAP_AMOUNT} Sats", level="WARN", @@ -741,9 +741,9 @@ class Logics: ) if not valid: context["swap_allowed"] = False - context[ - "swap_failure_reason" - ] = "Not enough onchain liquidity available to offer a swap" + context["swap_failure_reason"] = ( + "Not enough onchain liquidity available to offer a swap" + ) order.log( "Onchain payment option was not offered: onchain liquidity available to offer a swap", level="WARN", @@ -1019,6 +1019,8 @@ class Logics: order.log("Order expired while waiting for maker bond") order.log("Maker bond was cancelled") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 2.a) When maker cancels after bond @@ -1039,6 +1041,8 @@ class Logics: order.log("Order cancelled by maker while public or paused") order.log("Maker bond was unlocked") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 2.b) When maker cancels after bond and before taker bond is locked @@ -1058,6 +1062,8 @@ class Logics: order.log("Maker bond was unlocked") order.log("Taker bond was cancelled") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 3) When taker cancels before bond @@ -1070,6 +1076,8 @@ class Logics: order.log("Taker cancelled before locking the bond") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 4) When taker or maker cancel after bond (before escrow) @@ -1099,6 +1107,8 @@ class Logics: order.log("Maker bond was settled") order.log("Taker bond was unlocked") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 4.b) When taker cancel after bond (before escrow) @@ -1121,6 +1131,8 @@ class Logics: order.log("Taker bond was settled") order.log("Maker bond was unlocked") + nostr_send_order_event.delay(order_id=order.id) + return True, None # 5) When trade collateral has been posted (after escrow) @@ -1136,6 +1148,9 @@ class Logics: order.log( f"Taker Robot({user.robot.id},{user.username}) accepted the collaborative cancellation" ) + + nostr_send_order_event.delay(order_id=order.id) + return True, None # if the taker had asked, and now the maker does: cancel order, return everything @@ -1144,6 +1159,9 @@ class Logics: order.log( f"Maker Robot({user.robot.id},{user.username}) accepted the collaborative cancellation" ) + + nostr_send_order_event.delay(order_id=order.id) + return True, None # Otherwise just make true the asked for cancel flags @@ -1181,6 +1199,8 @@ class Logics: order.update_status(Order.Status.CCA) send_notification.delay(order_id=order.id, message="collaborative_cancelled") + nostr_send_order_event.delay(order_id=order.id) + order.log("Order was collaboratively cancelled") order.log("Maker bond was unlocked") order.log("Taker bond was unlocked") @@ -1208,7 +1228,7 @@ class Logics: order.save() # update all fields - send_order_nostr_event.delay(order_id=order.id, message="new") + nostr_send_order_event.delay(order_id=order.id) order.log(f"Order({order.id},{str(order)}) is public in the order book") return @@ -1352,6 +1372,9 @@ class Logics: except Exception: pass send_notification.delay(order_id=order.id, message="order_taken_confirmed") + + nostr_send_order_event.delay(order_id=order.id) + order.log( f"Contract formalized. Maker: Robot({order.maker.robot.id},{order.maker}). Taker: Robot({order.taker.robot.id},{order.taker}). API median price {order.currency.exchange_rate} {dict(Currency.currency_choices)[order.currency.currency]}/BTC. Premium is {order.premium}%. Contract size {order.last_satoshis} Sats" ) @@ -1743,11 +1766,15 @@ class Logics: order.log( f"Robot({user.robot.id},{user.username}) paused the public order" ) + + nostr_send_order_event.delay(order_id=order.id) elif order.status == Order.Status.PAU: order.update_status(Order.Status.PUB) order.log( f"Robot({user.robot.id},{user.username}) made public the paused order" ) + + nostr_send_order_event.delay(order_id=order.id) else: order.log( f"Robot({user.robot.id},{user.username}) tried to pause/unpause an order that was not public or paused", diff --git a/api/nostr.py b/api/nostr.py index 02effa65..4ebb5460 100644 --- a/api/nostr.py +++ b/api/nostr.py @@ -1,4 +1,6 @@ import pygeohash +import hashlib +import uuid from nostr_sdk import Keys, Client, EventBuilder, NostrSigner from api.models import Order from decouple import config @@ -7,7 +9,7 @@ from decouple import config class Nostr: """Simple nostr events manager to be used as a cache system for clients""" - async def send_new_order_event(self, order): + async def send_order_event(self, order): """Creates the event and sends it to the coordinator relay""" # Initialize with coordinator Keys keys = Keys.generate() @@ -23,12 +25,16 @@ class Nostr: print(f"Nostr event sent: {output}") def generate_tags(self, order): + hashed_id = hashlib.md5( + f"{config("COORDINATOR_ALIAS", cast=str)}{order.id}".encode("utf-8") + ).hexdigest() + return [ - ["d", order.id], + ["d", uuid.UUID(hashed_id)], ["name", order.maker.robot_name], ["k", order.type.lower()], ["f", order.currency], - ["s", Order.Status(order.status).label], + ["s", self.get_status_tag(order)], ["amt", order.last_satoshis], ["fa", order.amount], ["pm", order.payment_method.split(" ")], @@ -39,9 +45,16 @@ class Nostr: ], ["expiration", order.expires_at.timestamp()], ["y", "robosats"], - ["coordinator", config("COORDINATOR_ALIAS", cast=str)]["z", "order"], ["n", order.network], ["layer", "lightning"], ["g", pygeohash.encode(order.latitude, order.longitude)], ["bond", order.bond], + ["z", "order"], + ["coordinator", config("COORDINATOR_ALIAS", cast=str)], ] + + def get_status_tag(self, order): + if order.status == Order.Status.PUB: + return "pending" + else: + return "canceled" diff --git a/api/tasks.py b/api/tasks.py index fa1d44b7..a87c1f00 100644 --- a/api/tasks.py +++ b/api/tasks.py @@ -253,7 +253,7 @@ def cache_market(): @shared_task(name="", ignore_result=True, time_limit=120) -def send_order_nostr_event(order_id=None, message=None): +def nostr_send_order_event(order_id=None): if order_id: from api.models import Order from api.nostr import Nostr @@ -261,8 +261,7 @@ def send_order_nostr_event(order_id=None, message=None): order = Order.objects.get(id=order_id) nostr = Nostr() - if message == "new": - coroutine = nostr.send_new_order_event(order) + coroutine = nostr.send_order_event(order) if coroutine: loop = asyncio.get_event_loop() loop.run_until_complete(coroutine) diff --git a/docker-tests.yml b/docker-tests.yml index 41d3b5aa..21de001f 100644 --- a/docker-tests.yml +++ b/docker-tests.yml @@ -205,14 +205,14 @@ services: # - redis # network_mode: service:bitcoind - # strfry: - # build: https://github.com/hoytech/strfry.git - # container_name: test-strfry - # restart: unless-stopped - # volumes: - # - ./nodeapp/strfry/config/strfry.conf:/strfry/strfry.conf:r - # network_mode: service:bitcoind - + strfry: + image: dockurr/strfry:0.9.6 + container_name: test-strfry + restart: unless-stopped + volumes: + - ./nodeapp/strfry/db:/app/strfry-db + - ./nodeapp/strfry/config/strfry.conf:/etc/strfry.conf:r + network_mode: service:bitcoind volumes: redisdata: diff --git a/requirements.txt b/requirements.txt index 6e7ae047..e6200b67 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,3 +29,4 @@ drf-spectacular-sidecar==2024.7.1 django-cors-headers==4.4.0 base91==1.0.1 nostr-sdk==0.32.2 +pygeohash==1.2.0 diff --git a/tests/utils/trade.py b/tests/utils/trade.py index 7ac981b7..c6303b0a 100644 --- a/tests/utils/trade.py +++ b/tests/utils/trade.py @@ -5,7 +5,7 @@ from django.urls import reverse from api.management.commands.clean_orders import Command as CleanOrders from api.management.commands.follow_invoices import Command as FollowInvoices from api.models import Order -from api.tasks import follow_send_payment, send_notification, send_order_nostr_event +from api.tasks import follow_send_payment, send_notification, nostr_send_order_event from tests.utils.node import ( add_invoice, create_address, @@ -156,7 +156,7 @@ class Trade: wait_nodes_sync() @patch("api.tasks.send_notification.delay", send_notification) - @patch("api.tasks.send_order_nostr_event.delay", send_order_nostr_event) + @patch("api.tasks.nostr_send_order_event.delay", nostr_send_order_event) def publish_order(self): # Maker's first order fetch. Should trigger maker bond hold invoice generation. self.get_order()