示例#1
0
async def api_payment(payment_hash):
    payment = g.wallet.get_payment(payment_hash)

    if not payment:
        return jsonify({"message":
                        "Payment does not exist."}), HTTPStatus.NOT_FOUND
    elif not payment.pending:
        return jsonify({"paid": True}), HTTPStatus.OK

    try:
        if payment.is_uncheckable:
            pass
        elif payment.is_out:
            is_paid = not WALLET.get_payment_status(
                payment.checking_id).pending
        elif payment.is_in:
            is_paid = not WALLET.get_invoice_status(
                payment.checking_id).pending
    except Exception:
        return jsonify({"paid": False}), HTTPStatus.OK

    if is_paid:
        payment.set_pending(False)
        return jsonify({"paid": True}), HTTPStatus.OK

    return jsonify({"paid": False}), HTTPStatus.OK
示例#2
0
def lnurlwallet():
    memo = "LNbits LNURL funding"

    try:
        withdraw_res = handle_lnurl(request.args.get("lightning"))
        if not withdraw_res.ok:
            abort(
                HTTPStatus.BAD_REQUEST,
                f"Could not process LNURL-withdraw: {withdraw_res.error_msg}")
        if not isinstance(withdraw_res, LnurlWithdrawResponse):
            abort(HTTPStatus.BAD_REQUEST, "Not a valid LNURL-withdraw.")
    except LnurlException:
        abort(HTTPStatus.INTERNAL_SERVER_ERROR,
              "Could not process LNURL-withdraw.")

    try:
        ok, checking_id, payment_request, error_message = WALLET.create_invoice(
            withdraw_res.max_sats, memo)
    except Exception as e:
        ok, error_message = False, str(e)

    if not ok:
        abort(HTTPStatus.INTERNAL_SERVER_ERROR, error_message)

    r = requests.get(
        withdraw_res.callback.base,
        params={
            **withdraw_res.callback.query_params,
            **{
                "k1": withdraw_res.k1,
                "pr": payment_request
            }
        },
    )

    if not r.ok:
        abort(HTTPStatus.INTERNAL_SERVER_ERROR,
              "Could not process LNURL-withdraw.")

    for i in range(10):
        invoice_status = WALLET.get_invoice_status(checking_id)
        sleep(i)
        if not invoice_status.paid:
            continue
        break

    user = get_user(create_account().id)
    wallet = create_wallet(user_id=user.id)
    create_payment(
        wallet_id=wallet.id,
        checking_id=checking_id,
        amount=withdraw_res.max_sats * 1000,
        memo=memo,
        pending=invoice_status.pending,
    )

    return redirect(url_for("core.wallet", usr=user.id, wal=wallet.id))
示例#3
0
    def check_pending(self) -> None:
        if self.is_uncheckable:
            return

        if self.is_out:
            pending = WALLET.get_payment_status(self.checking_id)
        else:
            pending = WALLET.get_invoice_status(self.checking_id)

        self.set_pending(pending.pending)
示例#4
0
def api_payments():
    if "check_pending" in request.args:
        g.wallet.delete_expired_payments()

        for payment in g.wallet.get_payments(include_all_pending=True):
            if payment.is_out:
                payment.set_pending(WALLET.get_payment_status(payment.checking_id).pending)
            else:
                payment.set_pending(WALLET.get_invoice_status(payment.checking_id).pending)

    return jsonify(g.wallet.get_payments()), Status.OK
示例#5
0
async def api_payments():
    if "check_pending" in request.args:
        delete_expired_invoices()

        for payment in g.wallet.get_payments(complete=False,
                                             pending=True,
                                             exclude_uncheckable=True):
            if payment.is_out:
                payment.set_pending(
                    WALLET.get_payment_status(payment.checking_id).pending)
            else:
                payment.set_pending(
                    WALLET.get_invoice_status(payment.checking_id).pending)

    return jsonify(g.wallet.get_payments(pending=True)), HTTPStatus.OK
示例#6
0
def create_invoice(
    *,
    wallet_id: str,
    amount: int,
    memo: str,
    description_hash: Optional[bytes] = None,
    extra: Optional[Dict] = None,
) -> Tuple[str, str]:
    invoice_memo = None if description_hash else memo
    storeable_memo = memo

    ok, checking_id, payment_request, error_message = WALLET.create_invoice(
        amount=amount, memo=invoice_memo, description_hash=description_hash)
    if not ok:
        raise Exception(error_message or "Unexpected backend error.")

    invoice = bolt11.decode(payment_request)

    amount_msat = amount * 1000
    create_payment(
        wallet_id=wallet_id,
        checking_id=checking_id,
        payment_request=payment_request,
        payment_hash=invoice.payment_hash,
        amount=amount_msat,
        memo=storeable_memo,
        extra=extra,
    )

    g.db.commit()
    return invoice.payment_hash, payment_request
示例#7
0
def lndhub_gettxs():
    for payment in g.wallet.get_payments(complete=False,
                                         pending=True,
                                         outgoing=True,
                                         incoming=False,
                                         exclude_uncheckable=True):
        payment.set_pending(
            WALLET.get_payment_status(payment.checking_id).pending)

    limit = int(request.args.get("limit", 200))
    return jsonify([{
        "payment_preimage":
        payment.preimage,
        "payment_hash":
        payment.payment_hash,
        "fee_msat":
        payment.fee * 1000,
        "type":
        "paid_invoice",
        "fee":
        payment.fee,
        "value":
        int(payment.amount / 1000),
        "timestamp":
        payment.time,
        "memo":
        payment.memo if not payment.pending else "Payment in transition",
    } for payment in reversed(
        g.wallet.get_payments(
            pending=True, complete=True, outgoing=True, incoming=False)
        [:limit])])
示例#8
0
def lndhub_getuserinvoices():
    delete_expired_invoices()
    for invoice in g.wallet.get_payments(complete=False,
                                         pending=True,
                                         outgoing=False,
                                         incoming=True,
                                         exclude_uncheckable=True):
        invoice.set_pending(
            WALLET.get_invoice_status(invoice.checking_id).pending)

    limit = int(request.args.get("limit", 200))
    return jsonify([{
        "r_hash": to_buffer(invoice.payment_hash),
        "payment_request": invoice.bolt11,
        "add_index": "500",
        "description": invoice.memo,
        "payment_hash": invoice.payment_hash,
        "ispaid": not invoice.pending,
        "amt": int(invoice.amount / 1000),
        "expire_time": int(time.time() + 1800),
        "timestamp": invoice.time,
        "type": "user_invoice",
    } for invoice in reversed(
        g.wallet.get_payments(
            pending=True, complete=True, incoming=True, outgoing=False)
        [:limit])])
示例#9
0
async def check_invoice_status(wallet_id: str,
                               payment_hash: str) -> PaymentStatus:
    payment = await get_wallet_payment(wallet_id, payment_hash)
    if not payment:
        return PaymentStatus(None)

    return WALLET.get_invoice_status(payment.checking_id)
示例#10
0
def create_invoice(*, wallet_id: str, amount: int, memo: str) -> Tuple[str, str]:
    try:
        ok, checking_id, payment_request, error_message = WALLET.create_invoice(amount=amount, memo=memo)
    except Exception as e:
        ok, error_message = False, str(e)

    if not ok:
        raise Exception(error_message or "Unexpected backend error.")

    amount_msat = amount * 1000
    create_payment(wallet_id=wallet_id, checking_id=checking_id, amount=amount_msat, memo=memo)

    return checking_id, payment_request
示例#11
0
def pay_invoice(*,
                wallet_id: str,
                bolt11: str,
                max_sat: Optional[int] = None) -> str:
    temp_id = f"temp_{urlsafe_short_hash()}"
    try:
        invoice = bolt11_decode(bolt11)

        if invoice.amount_msat == 0:
            raise ValueError("Amountless invoices not supported.")

        if max_sat and invoice.amount_msat > max_sat * 1000:
            raise ValueError("Amount in invoice is too high.")

        fee_reserve = max(1000, int(invoice.amount_msat * 0.01))
        create_payment(
            wallet_id=wallet_id,
            checking_id=temp_id,
            amount=-invoice.amount_msat,
            fee=-fee_reserve,
            memo=temp_id,
        )

        wallet = get_wallet(wallet_id)
        assert wallet, "invalid wallet id"
        if wallet.balance_msat < 0:
            raise PermissionError("Insufficient balance.")

        ok, checking_id, fee_msat, error_message = WALLET.pay_invoice(bolt11)

        if ok:
            create_payment(
                wallet_id=wallet_id,
                checking_id=checking_id,
                amount=-invoice.amount_msat,
                fee=fee_msat,
                memo=invoice.description,
            )

    except Exception as e:
        ok, error_message = False, str(e)

    delete_payment(temp_id)

    if not ok:
        raise Exception(error_message or "Unexpected backend error.")

    return checking_id
示例#12
0
def api_ticket_send_ticket(checking_id):
    theticket = get_ticket(checking_id)
    try:
        is_paid = not WALLET.get_invoice_status(checking_id).pending
    except Exception:
        return jsonify({"message": "Not paid."}), HTTPStatus.NOT_FOUND

    if is_paid:
        wallet = get_wallet(theticket.wallet)
        payment = wallet.get_payment(checking_id)
        payment.set_pending(False)
        ticket = update_ticket(paid=True, checking_id=checking_id)

        return jsonify({"paid": True, "ticket_id": ticket.id}), HTTPStatus.OK

    return jsonify({"paid": False}), HTTPStatus.OK
示例#13
0
def api_amilkit(amilk_id):
    milk = get_amilk(amilk_id)
    memo = milk.id

    try:
        withdraw_res = handle_lnurl(milk.lnurl,
                                    response_class=LnurlWithdrawResponse)
    except LnurlException:
        abort(HTTPStatus.INTERNAL_SERVER_ERROR,
              "Could not process withdraw LNURL.")
    print(withdraw_res.max_sats)

    try:
        checking_id, payment_request = create_invoice(
            wallet_id=milk.wallet, amount=withdraw_res.max_sats, memo=memo)
        #print(payment_request)
    except Exception as e:
        error_message = False, str(e)

    r = requests.get(
        withdraw_res.callback.base,
        params={
            **withdraw_res.callback.query_params,
            **{
                "k1": withdraw_res.k1,
                "pr": payment_request
            }
        },
    )

    if not r.ok:

        abort(HTTPStatus.INTERNAL_SERVER_ERROR,
              "Could not process withdraw LNURL.")

    for i in range(10):
        invoice_status = WALLET.get_invoice_status(checking_id)
        sleep(i)
        if not invoice_status.paid:
            continue
        else:
            return jsonify({"paid": False}), HTTPStatus.OK
        break

    return jsonify({"paid": True}), HTTPStatus.OK
示例#14
0
def api_paywal_check_invoice(paywall_id):
    paywall = get_paywall(paywall_id)

    if not paywall:
        return jsonify({"message": "Paywall does not exist."}), HTTPStatus.NOT_FOUND

    try:
        is_paid = not WALLET.get_invoice_status(g.data["checking_id"]).pending
    except Exception:
        return jsonify({"paid": False}), HTTPStatus.OK

    if is_paid:
        wallet = get_wallet(paywall.wallet)
        payment = wallet.get_payment(g.data["checking_id"])
        payment.set_pending(False)

        return jsonify({"paid": True, "url": paywall.url, "remembers": paywall.remembers}), HTTPStatus.OK

    return jsonify({"paid": False}), HTTPStatus.OK
示例#15
0
def api_tpos_check_invoice(tpos_id, checking_id):
    tpos = get_tpos(tpos_id)

    if not tpos:
        return jsonify({"message": "TPoS does not exist."}), Status.NOT_FOUND

    try:
        is_paid = not WALLET.get_invoice_status(checking_id).pending
    except Exception:
        return jsonify({"paid": False}), Status.OK

    if is_paid:
        wallet = get_wallet(tpos.wallet)
        payment = wallet.get_payment(checking_id)
        payment.set_pending(False)

        return jsonify({"paid": True}), Status.OK

    return jsonify({"paid": False}), Status.OK
示例#16
0
def api_ticket_send_ticket(checking_id):

    form = get_form(g.data['form'])
    if not form:
        return jsonify({"message": "LNTicket does not exist."}), HTTPStatus.NOT_FOUND
    try:
        is_paid = not WALLET.get_invoice_status(checking_id).pending
    except Exception:
        return jsonify({"message": "Not paid."}), HTTPStatus.NOT_FOUND

    if is_paid:
        wallet = get_wallet(form.wallet)
        payment = wallet.get_payment(checking_id)
        payment.set_pending(False)
        create_ticket(wallet=form.wallet, **g.data)

        return jsonify({"paid": True}), HTTPStatus.OK

    return jsonify({"paid": False}), HTTPStatus.OK
示例#17
0
文件: crud.py 项目: tidley/lnbits
def get_diagonalleys_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]:
    if isinstance(wallet_ids, str):
        wallet_ids = [wallet_ids]

    with open_ext_db("diagonalley") as db:
        q = ",".join(["?"] * len(wallet_ids))
        rows = db.fetchall(f"SELECT * FROM orders WHERE wallet IN ({q})",
                           (*wallet_ids, ))
    for r in rows:
        PAID = WALLET.get_invoice_status(r["invoiceid"]).paid
        if PAID:
            with open_ext_db("diagonalley") as db:
                db.execute("UPDATE orders SET paid = ? WHERE id = ?", (
                    True,
                    r["id"],
                ))
                rows = db.fetchall(
                    f"SELECT * FROM orders WHERE wallet IN ({q})",
                    (*wallet_ids, ))
    return [Orders(**row) for row in rows]
示例#18
0
文件: tasks.py 项目: RhinoAK/lnbits
async def invoice_listener(nursery):
    async for checking_id in WALLET.paid_invoices_stream():
        nursery.start_soon(invoice_callback_dispatcher, checking_id)
示例#19
0
文件: tasks.py 项目: rootzoll/lnbits
async def invoice_listener():
    async for checking_id in WALLET.paid_invoices_stream():
        await run_on_pseudo_request(invoice_callback_dispatcher, checking_id)
示例#20
0
文件: tasks.py 项目: tomichec/lnbits
async def invoice_listener():
    async for checking_id in WALLET.paid_invoices_stream():
        print("> got a payment notification", checking_id)
        current_app.nursery.start_soon(invoice_callback_dispatcher,
                                       checking_id)
示例#21
0
async def invoice_listener():
    async with trio.open_nursery() as nursery:
        async for checking_id in WALLET.paid_invoices_stream():
            nursery.start_soon(invoice_callback_dispatcher, checking_id)
示例#22
0
def pay_invoice(*,
                wallet_id: str,
                payment_request: str,
                max_sat: Optional[int] = None,
                extra: Optional[Dict] = None) -> str:
    temp_id = f"temp_{urlsafe_short_hash()}"
    internal_id = f"internal_{urlsafe_short_hash()}"

    invoice = bolt11.decode(payment_request)
    if invoice.amount_msat == 0:
        raise ValueError("Amountless invoices not supported.")
    if max_sat and invoice.amount_msat > max_sat * 1000:
        raise ValueError("Amount in invoice is too high.")

    # put all parameters that don't change here
    PaymentKwargs = TypedDict(
        "PaymentKwargs",
        {
            "wallet_id": str,
            "payment_request": str,
            "payment_hash": str,
            "amount": int,
            "memo": str,
            "extra": Optional[Dict],
        },
    )
    payment_kwargs: PaymentKwargs = dict(
        wallet_id=wallet_id,
        payment_request=payment_request,
        payment_hash=invoice.payment_hash,
        amount=-invoice.amount_msat,
        memo=invoice.description or "",
        extra=extra,
    )

    # check_internal() returns the checking_id of the invoice we're waiting for
    internal = check_internal(invoice.payment_hash)
    if internal:
        # create a new payment from this wallet
        create_payment(checking_id=internal_id,
                       fee=0,
                       pending=False,
                       **payment_kwargs)
    else:
        # create a temporary payment here so we can check if
        # the balance is enough in the next step
        fee_reserve = max(1000, int(invoice.amount_msat * 0.01))
        create_payment(checking_id=temp_id, fee=-fee_reserve, **payment_kwargs)

    # do the balance check
    wallet = get_wallet(wallet_id)
    assert wallet
    if wallet.balance_msat < 0:
        g.db.rollback()
        raise PermissionError("Insufficient balance.")
    else:
        g.db.commit()

    if internal:
        # mark the invoice from the other side as not pending anymore
        # so the other side only has access to his new money when we are sure
        # the payer has enough to deduct from
        update_payment_status(checking_id=internal, pending=False)
    else:
        # actually pay the external invoice
        ok, checking_id, fee_msat, error_message = WALLET.pay_invoice(
            payment_request)
        if ok:
            create_payment(checking_id=checking_id,
                           fee=fee_msat,
                           **payment_kwargs)
            delete_payment(temp_id)
        else:
            raise Exception(error_message
                            or "Failed to pay_invoice on backend.")

    g.db.commit()
    return invoice.payment_hash