import pygeohash import hashlib import uuid from asgiref.sync import sync_to_async from nostr_sdk import Keys, Client, EventBuilder, NostrSigner, Kind, Tag from api.models import Order from decouple import config class Nostr: """Simple nostr events manager to be used as a cache system for clients""" async def send_order_event(self, order): """Creates the event and sends it to the coordinator relay""" if config("NOSTR_NSEC", cast=str, default="") == "": return print("Sending nostr event") # Initialize with coordinator Keys keys = Keys.parse(config("NOSTR_NSEC", cast=str)) signer = NostrSigner.keys(keys) client = Client(signer) # Add relays and connect await client.add_relays(["ws://localhost:7777"]) await client.connect() robot_name = await self.get_robot_name(order) robot_hash_id = await self.get_robot_hash_id(order) currency = await self.get_robot_currency(order) event = EventBuilder( Kind(38383), "", self.generate_tags(order, robot_name, robot_hash_id, currency), ).to_event(keys) await client.send_event(event) print(f"Nostr event sent: {event.as_json()}") @sync_to_async def get_robot_name(self, order): return order.maker.username @sync_to_async def get_robot_hash_id(self, order): return order.maker.robot.hash_id @sync_to_async def get_robot_currency(self, order): return str(order.currency) def generate_tags(self, order, robot_name, robot_hash_id, currency): hashed_id = hashlib.md5( f"{config("COORDINATOR_ALIAS", cast=str)}{order.id}".encode("utf-8") ).hexdigest() tags = [ Tag.parse(["d", str(uuid.UUID(hashed_id))]), Tag.parse(["name", robot_name, robot_hash_id]), Tag.parse(["k", "sell" if order.type == Order.Types.SELL else "buy"]), Tag.parse(["f", currency]), Tag.parse(["s", self.get_status_tag(order)]), Tag.parse(["amt", "0"]), Tag.parse( ["fa"] + ( [str(order.amount)] if not order.has_range else [str(order.min_amount), str(order.max_amount)] ) ), Tag.parse(["pm"] + order.payment_method.split(" ")), Tag.parse(["premium", str(order.premium)]), Tag.parse( [ "source", f"http://{config("HOST_NAME")}/order/{config("COORDINATOR_ALIAS", cast=str).lower()}/{order.id}", ] ), Tag.parse( [ "expiration", str(int(order.expires_at.timestamp())), str(order.escrow_duration), ] ), Tag.parse(["y", "robosats", config("COORDINATOR_ALIAS", cast=str).lower()]), Tag.parse(["n", str(config("NETWORK"))]), Tag.parse(["layer"] + self.get_layer_tag(order)), Tag.parse(["bond", str(order.bond_size)]), Tag.parse(["z", "order"]), ] if order.latitude and order.longitude: tags.extend( [Tag.parse(["g", pygeohash.encode(order.latitude, order.longitude)])] ) return tags def get_status_tag(self, order): if order.status == Order.Status.PUB: return "pending" else: return "success" def get_layer_tag(self, order): if order.type == Order.Types.SELL: return ["onchain", "lightning"] else: return ["lightning"]