class LightningDaemon(object): def __init__(self, daemon_rpc): self.rpc = LightningRpc(daemon_rpc) def invoice_c_lightning(self, msatoshi, label, description): expiry = INVOICE_EXPIRY + random.randint(3, 9) try: result = self.rpc.invoice(msatoshi, label, description, expiry=expiry) logging.info("invoicing daemon. got: %s" % json.dumps(result, indent=1, sort_keys=True)) return result except: return None def get_c_lightning_invoices(self): try: return self.rpc.listinvoices() except: return None #logging.info(json.dumps(result, indent=1, sort_keys=True)) def _delete(self, label, state="paid"): try: result = self.rpc.delinvoice(label, state) return result except IOError: # unpaid could have expired in the last split second due # to a race, so try again if state == "unpaid": result = self.rpc.delinvoice(label, "expired") return result def delete(self, label, state="paid"): try: return self._delete(label, state=state) except: return None def getinfo(self): try: return self.rpc.getinfo() except: return None def listfunds(self): try: return self.rpc.listfunds() except: return None def listnodes(self): try: return self.rpc.listnodes() except: return None
class Daemon(object): def __init__(self): self.rpc = LightningRpc(RPC_FILE) def _gen_new_label(self): label_bytes = uuid.uuid4().bytes label_str = b64encode(label_bytes).decode("utf8") return label_str def invoice(self): msatoshis = 12000 description = "f**k you, pay me" label = self._gen_new_label() i = self.rpc.invoice(msatoshis, label, description) return {'label': label, 'bolt11': i['bolt11']}
class CLightningClient(LightningClient): """Access a c-lightning instance using the Python API.""" def __init__( self, rpc_path: str, ) -> None: self.rpc_path = rpc_path def init(self): # Create an instance of the LightningRpc object using the Core Lightning daemon on your computer. logger.info('initializing clightning client: {}'.format(self.rpc_path)) self.lrpc = LightningRpc(self.rpc_path) def pay_invoice(self, payment_request: str) -> Payment: payment = self.lrpc.pay(payment_request) if payment['status'] == 'complete': return Payment( payment_preimage=bytes.fromhex(payment['payment_preimage']), payment_error='', ) else: return Payment( payment_preimage=b'', payment_error='Payment failed.', ) def get_info(self) -> Info: info = self.lrpc.getinfo() pubkey = info['id'] binding = info.get('binding') uris = [] if binding: for b in binding: address = b['address'] if ':' not in address: # TODO: Change type of uri to LightningAddress. port = b['port'] uri = f"{pubkey}@{address}:{port}" uris.append(uri) return Info(uris=uris, ) def decode_pay_req(self, payment_request: str) -> PayReq: pay_req = self.lrpc.decodepay(payment_request) return PayReq( payment_hash=bytes.fromhex(pay_req['payment_hash']), payment_point=b'', # TODO: Use real payment point. num_msat=pay_req['amount_msat'].millisatoshis, destination=pay_req['payee'], timestamp=int(pay_req['created_at']), expiry=int(pay_req['expiry']), ) def create_invoice(self, preimage: bytes, amount_msat: int) -> Invoice: created_invoice = self.lrpc.invoice( amount_msat, label=str(uuid.uuid4()), description="Squeaknode invoice", preimage=preimage.hex(), ) creation_time = int(time.time()) expiry = int(created_invoice['expires_at']) - creation_time return Invoice( r_hash=bytes.fromhex(created_invoice['payment_hash']), payment_request=created_invoice['bolt11'], value_msat=amount_msat, settled=False, settle_index=0, creation_date=creation_time, expiry=expiry, ) def subscribe_invoices(self, settle_index: int) -> InvoiceStream: def cancel_fn(): return None def get_invoice_stream(): try: pay_index = settle_index while True: payment = self.lrpc.waitanyinvoice(lastpay_index=pay_index) if payment['status'] == 'paid': pay_index = payment.get('pay_index') or 0 yield Invoice( r_hash=bytes.fromhex(payment['payment_hash']), payment_request=payment.get('bolt11') or '', value_msat=payment.get('value_msat'), settled=True, settle_index=pay_index, creation_date=0, # This value is ignored. expiry=payment['expires_at'], ) except Exception: raise InvoiceSubscriptionError() return InvoiceStream( cancel=cancel_fn, result_stream=get_invoice_stream(), )
class clightning: def __init__(self, node_config): from pyln.client import LightningRpc self.config = node_config self.is_onchain = False for i in range(config.connection_attempts): try: if config.tunnel_host is None: rpc_file = self.config['clightning_rpc_file'] else: rpc_file = "lightning-rpc" logging.info( "Attempting to connect to clightning with unix domain socket: {}" .format(rpc_file)) self.clightning = LightningRpc(rpc_file) logging.info("Getting clightning info...") info = self.clightning.getinfo() logging.info(info) logging.info("Successfully connected to clightning.") break except Exception as e: logging.error(e) if i < 5: time.sleep(2) else: time.sleep(60) logging.info("Attempting again... {}/{}...".format( i + 1, config.connection_attempts)) else: raise Exception( "Could not connect to clightning. Check your port tunneling settings and try again." ) logging.info("Ready for payments requests.") return def create_qr(self, uuid, address, value): qr_str = "{}".format(address.upper()) img = qrcode.make(qr_str) img.save("static/qr_codes/{}.png".format(uuid)) return def get_info(self): return self.clightning.getinfo() def get_uri(self): info = self.get_info() address = info["address"][0] return info["id"] + "@" + address["address"] + ":" + str( address["port"]) # Create lightning invoice def create_clightning_invoice(self, btc_amount, label, expiry): # Multiplying by 10^8 to convert to satoshi units msats_amount = int(float(btc_amount) * 10**(3 + 8)) lnd_invoice = self.clightning.invoice(msats_amount, label, "SatSale-{}".format(label), expiry) return lnd_invoice["bolt11"], lnd_invoice["payment_hash"] def get_address(self, amount, label, expiry): address, r_hash = self.create_clightning_invoice(amount, label, expiry) return address, r_hash # Check whether the payment has been paid def check_payment(self, uuid): invoices = self.clightning.listinvoices(uuid)["invoices"] if len(invoices) == 0: logging.error("Could not find invoice on node. Something's wrong.") return 0, 0 invoice = invoices[0] if invoice["status"] != "paid": conf_paid = 0 unconf_paid = 0 else: # Store amount paid and convert to BTC units conf_paid = int(invoice["msatoshi_received"]) / 10**(3 + 8) unconf_paid = 0 return conf_paid, unconf_paid