mirror of https://github.com/lukechilds/lnbits.git
committed by
GitHub
34 changed files with 604 additions and 319 deletions
@ -1,25 +1,33 @@ |
|||||
name: Run Linters |
name: Linters |
||||
|
|
||||
on: [push, pull_request] |
on: |
||||
|
push: |
||||
|
branches: [ master ] |
||||
|
pull_request: |
||||
|
branches: [ master ] |
||||
|
|
||||
jobs: |
jobs: |
||||
mypy: |
black: |
||||
runs-on: ubuntu-latest |
runs-on: ubuntu-latest |
||||
steps: |
steps: |
||||
- name: Checkout |
- uses: actions/checkout@v2 |
||||
uses: actions/checkout@v1 |
- run: sudo apt-get install python3-venv |
||||
- name: Run MyPy python type checker |
- run: python3 -m venv venv |
||||
uses: jpetrucciani/mypy-check@master |
- run: ./venv/bin/pip install black |
||||
with: |
- run: make checkblack |
||||
path: 'lnbits' |
|
||||
|
|
||||
prettier: |
prettier: |
||||
runs-on: ubuntu-latest |
runs-on: ubuntu-latest |
||||
steps: |
steps: |
||||
- name: Checkout |
- uses: actions/checkout@v2 |
||||
uses: actions/checkout@v1 |
- run: npm install |
||||
- name: Check JS code formatting convention |
- run: make checkprettier |
||||
uses: creyD/prettier_action@v2.2 |
mypy: |
||||
with: |
runs-on: ubuntu-latest |
||||
dry: True |
steps: |
||||
prettier_options: --write lnbits/static/js/** lnbits/core/static/js/** lnbits/extensions/*/templates/** |
- uses: actions/checkout@v2 |
||||
|
- run: sudo apt-get install python3-venv |
||||
|
- run: sudo apt-get install libev-dev |
||||
|
- run: python3 -m venv venv |
||||
|
- run: ./venv/bin/pip install -r requirements.txt |
||||
|
- run: ./venv/bin/pip install mypy |
||||
|
- run: make mypy |
||||
|
@ -1,10 +1,20 @@ |
|||||
all: prettier mypy black |
all: format check |
||||
|
|
||||
|
format: prettier black |
||||
|
|
||||
|
check: mypy checkprettier checkblack |
||||
|
|
||||
prettier: $(shell find lnbits -name "*.js" -name ".html") |
prettier: $(shell find lnbits -name "*.js" -name ".html") |
||||
./node_modules/.bin/prettier --write lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js |
./node_modules/.bin/prettier --write lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js |
||||
|
|
||||
|
black: $(shell find lnbits -name "*.py") |
||||
|
./venv/bin/black --line-length 120 lnbits |
||||
|
|
||||
mypy: $(shell find lnbits -name "*.py") |
mypy: $(shell find lnbits -name "*.py") |
||||
mypy lnbits |
./venv/bin/mypy lnbits |
||||
|
|
||||
black: $(shell find lnbits -name "*.py") |
checkprettier: $(shell find lnbits -name "*.js" -name ".html") |
||||
black lnbits |
./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js |
||||
|
|
||||
|
checkblack: $(shell find lnbits -name "*.py") |
||||
|
./venv/bin/black --check --line-length 120 lnbits |
||||
|
@ -1,72 +1,112 @@ |
|||||
from typing import Optional, Tuple |
from typing import Optional, Tuple, Dict, TypedDict |
||||
|
|
||||
from lnbits.bolt11 import decode as bolt11_decode # type: ignore |
from lnbits import bolt11 |
||||
from lnbits.helpers import urlsafe_short_hash |
from lnbits.helpers import urlsafe_short_hash |
||||
from lnbits.settings import WALLET |
from lnbits.settings import WALLET |
||||
|
from lnbits.wallets.base import PaymentStatus |
||||
|
|
||||
from .crud import get_wallet, create_payment, delete_payment |
from .crud import get_wallet, create_payment, delete_payment, check_internal, update_payment_status, get_wallet_payment |
||||
|
|
||||
|
|
||||
def create_invoice(*, wallet_id: str, amount: int, memo: str, description_hash: bytes = None) -> Tuple[str, str]: |
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 |
||||
|
|
||||
try: |
|
||||
ok, checking_id, payment_request, error_message = WALLET.create_invoice( |
ok, checking_id, payment_request, error_message = WALLET.create_invoice( |
||||
amount=amount, memo=memo, description_hash=description_hash |
amount=amount, memo=invoice_memo, description_hash=description_hash |
||||
) |
) |
||||
except Exception as e: |
|
||||
ok, error_message = False, str(e) |
|
||||
|
|
||||
if not ok: |
if not ok: |
||||
raise Exception(error_message or "Unexpected backend error.") |
raise Exception(error_message or "Unexpected backend error.") |
||||
|
|
||||
|
invoice = bolt11.decode(payment_request) |
||||
|
|
||||
amount_msat = amount * 1000 |
amount_msat = amount * 1000 |
||||
create_payment(wallet_id=wallet_id, checking_id=checking_id, amount=amount_msat, memo=memo) |
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, |
||||
|
) |
||||
|
|
||||
return checking_id, payment_request |
return invoice.payment_hash, payment_request |
||||
|
|
||||
|
|
||||
def pay_invoice(*, wallet_id: str, bolt11: str, max_sat: Optional[int] = None) -> str: |
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()}" |
temp_id = f"temp_{urlsafe_short_hash()}" |
||||
try: |
internal_id = f"internal_{urlsafe_short_hash()}" |
||||
invoice = bolt11_decode(bolt11) |
|
||||
|
|
||||
|
invoice = bolt11.decode(payment_request) |
||||
if invoice.amount_msat == 0: |
if invoice.amount_msat == 0: |
||||
raise ValueError("Amountless invoices not supported.") |
raise ValueError("Amountless invoices not supported.") |
||||
|
|
||||
if max_sat and invoice.amount_msat > max_sat * 1000: |
if max_sat and invoice.amount_msat > max_sat * 1000: |
||||
raise ValueError("Amount in invoice is too high.") |
raise ValueError("Amount in invoice is too high.") |
||||
|
|
||||
fee_reserve = max(1000, int(invoice.amount_msat * 0.01)) |
# put all parameters that don't change here |
||||
create_payment( |
PaymentKwargs = TypedDict( |
||||
wallet_id=wallet_id, checking_id=temp_id, amount=-invoice.amount_msat, fee=-fee_reserve, memo=temp_id, |
"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) |
wallet = get_wallet(wallet_id) |
||||
assert wallet, "invalid wallet id" |
assert wallet, "invalid wallet id" |
||||
if wallet.balance_msat < 0: |
if wallet.balance_msat < 0: |
||||
raise PermissionError("Insufficient balance.") |
raise PermissionError("Insufficient balance.") |
||||
|
|
||||
ok, checking_id, fee_msat, error_message = WALLET.pay_invoice(bolt11) |
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: |
if ok: |
||||
create_payment( |
create_payment(checking_id=checking_id, fee=fee_msat, **payment_kwargs) |
||||
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) |
delete_payment(temp_id) |
||||
|
|
||||
if not ok: |
if not ok: |
||||
raise Exception(error_message or "Unexpected backend error.") |
raise Exception(error_message or "Unexpected backend error.") |
||||
|
|
||||
return checking_id |
return invoice.payment_hash |
||||
|
|
||||
|
|
||||
|
def check_invoice_status(wallet_id: str, payment_hash: str) -> PaymentStatus: |
||||
|
payment = get_wallet_payment(wallet_id, payment_hash) |
||||
|
if not payment: |
||||
|
return PaymentStatus(None) |
||||
|
|
||||
def check_payment(*, checking_id: str) -> str: |
return WALLET.get_invoice_status(payment.checking_id) |
||||
pass |
|
||||
|
@ -1,8 +1,5 @@ |
|||||
{ |
{ |
||||
"devDependencies": { |
"devDependencies": { |
||||
"prettier": "^2.0.5" |
"prettier": "^2.0.5" |
||||
}, |
|
||||
"scripts": { |
|
||||
"lint": "prettier --write lnbits/static/js/** lnbits/core/static/js/** lnbits/extensions/*/templates/**" |
|
||||
} |
} |
||||
} |
} |
||||
|
Loading…
Reference in new issue