#!/usr/bin/python3 import os import time import logging import requests import json import qr import math from PIL import ImageDraw, Image import qrcode import config import display import utils # TODO: Add variable to set certificate check to true or false # TODO: Add evaluation for credentials after scanning logger = logging.getLogger("LNTXBOT") def print_conf(): print(config.conf["lntxbot"]["creds"]) def request_lnurl(amt): """Request a new lnurl for 'amt' from the server """ data = { "satoshis": str(math.floor(amt)), } response = requests.post( str(config.conf["lntxbot"]["url"]) + "/generatelnurlwithdraw", headers={"Authorization": "Basic %s" % config.conf["lntxbot"]["creds"]}, data=json.dumps(data), ) return response.json() def generate_lnurl_qr(lnurl): """Generate an lnurl qr code from a lnurl """ lnurlqr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=2, border=1, ) lnurlqr.add_data(lnurl.upper()) logger.info("LNURL QR code generated") return lnurlqr.make_image() def draw_lnurl_qr(qr_img): """draw a lnurl qr code on the e-ink screen """ image = Image.new("1", config.PAPIRUS.size, config.BLACK) draw = ImageDraw.Draw(image) draw.bitmap((0, 0), qr_img, fill=config.WHITE) draw.text( (110, 25), "Scan to", fill=config.WHITE, font=utils.create_font("freemonobold", 16), ) draw.text( (110, 45), "receive", fill=config.WHITE, font=utils.create_font("freemonobold", 16), ) config.PAPIRUS.display(image) config.PAPIRUS.update() def get_lnurl_balance(): """Query the lnurl balance from the server and return the ["BTC"]["AvailableBalance"] value """ response = requests.post( str(config.conf["lntxbot"]["url"]) + "/balance", headers={"Authorization": "Basic %s" % config.conf["lntxbot"]["creds"]}, ) return response.json()["BTC"]["AvailableBalance"] def wait_for_balance_update(start_balance, timeout): """Loops waiting for any balance change on the lnurl and returns True if this happens before the timeout """ start_time = time.time() success = False # loop while we wait for the balance to get updated while True and (time.time() < start_time + timeout): new_balance = get_lnurl_balance() if start_balance == new_balance: print("Balance: " + str(start_balance) + " (no changes)") time.sleep(3) else: print( "Balance: " + str(start_balance) + " | New Balance:" + str(new_balance) ) success = True break return success def process_using_lnurl(amt): """Processes receiving an amount using the lnurl scheme """ # get the new lnurl display.update_lnurl_generation() logger.info("LNURL requested") print("LNURL requested") lnurl = request_lnurl(amt) print(lnurl["lnurl"]) # Check EPD_SIZE is defined utils.check_epd_size() # create a qr code image and print it to terminal qr_img = generate_lnurl_qr(lnurl["lnurl"]) qr_img = qr_img.resize((96, 96), resample=0) # draw the qr code on the e-ink screen draw_lnurl_qr(qr_img) # get the balance? back from the bot start_balance = get_lnurl_balance() print(start_balance) # loop while we wait for a balance update or until timeout reached success = wait_for_balance_update(start_balance, timeout=90) if success: display.update_thankyou_screen() logger.info("LNURL withdrawal succeeded") return else: # TODO: I think we should handle a failure here logger.error("LNURL withdrawal failed (within 90 seconds)") def scan_creds(): """Scan lntxbot credentials """ attempts = 0 while attempts < 4: qrcode = qr.scan() if qrcode: credentials = qrcode if not credentials: attempts += 1 else: return credentials attempts += 1 logger.error("4 failed scanning attempts.") print("4 failed attempts ... try again.") raise utils.ScanError def payout(amt, payment_request): """Attempts to pay a BOLT11 invoice """ data = { "invoice": payment_request, "amount": math.floor(amt), } response = requests.post( str(config.conf["lntxbot"]["url"]) + "/payinvoice", headers={"Authorization": "Basic %s" % config.conf["lntxbot"]["creds"]}, data=json.dumps(data), )