Merge remote-tracking branch 'origin/main' into extension_install_02

This commit is contained in:
ben 2023-01-26 12:39:11 +00:00
commit 39f0000fa5
23 changed files with 371 additions and 170 deletions

View File

@ -4,7 +4,6 @@ docker
docs
tests
venv
tools
lnbits/static/css/*
lnbits/static/bundle.js

View File

@ -66,6 +66,9 @@ LNBITS_BACKEND_WALLET_CLASS=VoidWallet
# VoidWallet is just a fallback that works without any actual Lightning capabilities,
# just so you can see the UI before dealing with this file.
# Invoice expiry for LND, CLN, Eclair, LNbits funding sources
LIGHTNING_INVOICE_EXPIRY=600
# Set one of these blocks depending on the wallet kind you chose above:
# ClicheWallet

View File

@ -134,6 +134,49 @@ jobs:
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
LNbitsWallet:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9"]
poetry-version: ["1.3.1"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Set up Poetry ${{ matrix.poetry-version }}
uses: abatilo/actions-poetry@v2
with:
poetry-version: ${{ matrix.poetry-version }}
- name: Setup Regtest
run: |
docker build -t lnbitsdocker/lnbits-legend .
git clone https://github.com/lnbits/legend-regtest-enviroment.git docker
cd docker
chmod +x ./tests
./tests
sudo chmod -R a+rwx .
docker exec lnbits-legend-lnbits-1 /bin/bash -c "poetry run python tools/create_fake_admin.py"
- name: Install dependencies
run: |
poetry install
- name: Run tests
env:
PYTHONUNBUFFERED: 1
PORT: 5123
LNBITS_DATA_FOLDER: ./data
LNBITS_BACKEND_WALLET_CLASS: LNbitsWallet
LNBITS_ENDPOINT: http://localhost:5001
LNBITS_KEY: "d08a3313322a4514af75d488bcc27eee"
run: |
sudo chmod -R a+rwx . && rm -rf ./data && mkdir -p ./data
make test-real-wallet
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
EclairWallet:
runs-on: ubuntu-latest
strategy:
@ -176,4 +219,4 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
file: ./coverage.xml

View File

@ -13,7 +13,7 @@ RUN mkdir -p lnbits/data
COPY . .
RUN poetry config virtualenvs.create false
RUN poetry install --only main --no-root
RUN poetry install --only main
RUN poetry run python build.py
ENV LNBITS_PORT="5000"

View File

@ -26,8 +26,8 @@ sudo apt install python3.9 python3.9-distutils
curl -sSL https://install.python-poetry.org | python3 -
# Once the above poetry install is completed, use the installation path printed to terminal and replace in the following command
export PATH="/home/user/.local/bin:$PATH"
# Next command, you can exchange with python3.10 or newer versions.
export PATH="/home/user/.local/bin:$PATH"
# Next command, you can exchange with python3.10 or newer versions.
# Identify your version with python3 --version and specify in the next line
# command is only needed when your default python is not ^3.9 or ^3.10
poetry env use python3.9
@ -36,7 +36,7 @@ poetry install --only main
mkdir data
cp .env.example .env
# set funding source amongst other options
nano .env
nano .env
```
#### Running the server
@ -45,7 +45,7 @@ nano .env
poetry run lnbits
# To change port/host pass 'poetry run lnbits --port 9000 --host 0.0.0.0'
# adding --debug in the start-up command above to help your troubleshooting and generate a more verbose output
# Note that you have to add the line DEBUG=true in your .env file, too.
# Note that you have to add the line DEBUG=true in your .env file, too.
```
#### Updating the server
@ -58,7 +58,7 @@ poetry install --only main
# Start LNbits with `poetry run lnbits`
```
## Option 2: Nix
## Option 2: Nix
> note: currently not supported while we make some architectural changes on the path to leave beta
@ -105,22 +105,30 @@ If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`
## Option 4: Docker
use latest version from docker hub
```sh
docker pull lnbitsdocker/lnbits-legend
wget https://raw.githubusercontent.com/lnbits/lnbits/main/.env.example -O .env
mkdir data
docker run --detach --publish 5000:5000 --name lnbits --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbitsdocker/lnbits-legend
```
build the image yourself
```sh
git clone https://github.com/lnbits/lnbits.git
cd lnbits
docker build -t lnbits .
docker build -t lnbitsdocker/lnbits-legend .
cp .env.example .env
mkdir data
docker run --detach --publish 5000:5000 --name lnbits-legend --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbits-legend
docker run --detach --publish 5000:5000 --name lnbits --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbitsdocker/lnbits-legend
```
## Option 5: Fly.io
Fly.io is a docker container hosting platform that has a generous free tier. You can host LNbits for free on Fly.io for personal use.
First, sign up for an account at [Fly.io](https://fly.io) (no credit card required).
First, sign up for an account at [Fly.io](https://fly.io) (no credit card required).
Then, install the Fly.io CLI onto your device [here](https://fly.io/docs/getting-started/installing-flyctl/).
Then, install the Fly.io CLI onto your device [here](https://fly.io/docs/getting-started/installing-flyctl/).
After install is complete, the command will output a command you should copy/paste/run to get `fly` into your `$PATH`. Something like:
@ -145,7 +153,7 @@ fly launch
You'll be prompted to enter an app name, region, postgres (choose no), deploy now (choose no).
You'll now find a file in the directory called `fly.toml`. Open that file and modify/add the following settings.
You'll now find a file in the directory called `fly.toml`. Open that file and modify/add the following settings.
Note: Be sure to replace `${PUT_YOUR_LNBITS_ENV_VARS_HERE}` with all relevant environment variables in `.env` or `.env.example`. Environment variable strings should be quoted here, so if in `.env` you have `LNBITS_ENDPOINT=https://legend.lnbits.com` in `fly.toml` you should have `LNBITS_ENDPOINT="https://legend.lnbits.com"`.
@ -169,7 +177,7 @@ kill_timeout = 30
LNBITS_FORCE_HTTPS=true
FORWARDED_ALLOW_IPS="*"
LNBITS_DATA_FOLDER="/data"
${PUT_YOUR_LNBITS_ENV_VARS_HERE}
...

View File

@ -65,6 +65,7 @@ async def create_invoice(
memo: str,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
expiry: Optional[int] = None,
extra: Optional[Dict] = None,
webhook: Optional[str] = None,
internal: Optional[bool] = False,
@ -80,6 +81,7 @@ async def create_invoice(
memo=invoice_memo,
description_hash=description_hash,
unhashed_description=unhashed_description,
expiry=expiry or settings.lightning_invoice_expiry,
)
if not ok:
raise InvoiceFailure(error_message or "unexpected backend error.")

View File

@ -16,7 +16,7 @@
</div>
</div>
<div class="row q-col-gutter-md">
<div class="col-12 col-md-6">
<div class="col-12 col-md-4">
<div class="row">
<div class="col-12">
<p>Active Funding<small> (Requires server restart)</small></p>
@ -30,28 +30,40 @@
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="col-12">
<p>Fee reserve</p>
<div class="row q-col-gutter-md">
<div class="col-6">
<q-input
type="number"
filled
v-model="formData.lnbits_reserve_fee_min"
label="Reserve fee in msats"
>
</q-input>
</div>
<div class="col-6">
<q-input
type="number"
filled
name="lnbits_reserve_fee_percent"
v-model="formData.lnbits_reserve_fee_percent"
label="Reserve fee in percent"
step="0.1"
></q-input>
<div class="col-12 col-md-8">
<div class="row q-col-gutter-md">
<div class="col-12 col-md-4">
<p>Invoice Expiry</p>
<q-input
filled
v-model="formData.lightning_invoice_expiry"
label="Invoice expiry (seconds)"
mask="#######"
>
</q-input>
</div>
<div class="col-12 col-md-8">
<p>Fee reserve</p>
<div class="row q-col-gutter-md">
<div class="col-6">
<q-input
type="number"
filled
v-model="formData.lnbits_reserve_fee_min"
label="Reserve fee in msats"
>
</q-input>
</div>
<div class="col-6">
<q-input
type="number"
filled
name="lnbits_reserve_fee_percent"
v-model="formData.lnbits_reserve_fee_percent"
label="Reserve fee in percent"
step="0.1"
></q-input>
</div>
</div>
</div>
</div>

View File

@ -9,6 +9,7 @@
:disabled="!checkChanges"
>
<q-tooltip v-if="checkChanges"> Save your changes </q-tooltip>
<q-badge
v-if="checkChanges"
color="red"
@ -17,6 +18,7 @@
style="padding: 6px; border-radius: 6px"
/>
</q-btn>
<q-btn
v-if="isSuperUser"
label="Restart server"
@ -26,6 +28,7 @@
<q-tooltip v-if="needsRestart">
Restart the server for changes to take effect
</q-tooltip>
<q-badge
v-if="needsRestart"
color="red"
@ -34,6 +37,7 @@
style="padding: 6px; border-radius: 6px"
/>
</q-btn>
<q-btn
v-if="isSuperUser"
label="Topup"
@ -42,11 +46,13 @@
>
<q-tooltip> Add funds to a wallet. </q-tooltip>
</q-btn>
<!-- <q-btn
label="Download Database Backup"
flat
@click="downloadBackup"
></q-btn> -->
<q-btn
flat
v-if="isSuperUser"
@ -59,6 +65,7 @@
</q-btn>
</div>
</div>
<div class="row q-col-gutter-md justify-center">
<div class="col q-gutter-y-md">
<q-card>
@ -70,16 +77,19 @@
label="Funding"
@update="val => tab = val.name"
></q-tab>
<q-tab
name="users"
label="Users"
@update="val => tab = val.name"
></q-tab>
<q-tab
name="server"
label="Server"
@update="val => tab = val.name"
></q-tab>
<q-tab
name="theme"
label="Theme"
@ -88,6 +98,7 @@
</q-tabs>
</div>
</div>
<q-form name="settings_form" id="settings_form">
<q-tab-panels v-model="tab" animated>
{% include "admin/_tab_funding.html" %} {% include
@ -98,10 +109,12 @@
</q-card>
</div>
</div>
<q-dialog v-if="isSuperUser" v-model="topUpDialog.show" position="top">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<q-form class="q-gutter-md">
<p>TopUp a wallet</p>
<div class="row">
<div class="col-12">
<q-input
@ -112,8 +125,10 @@
label="Wallet ID"
hint="Use the wallet ID to topup any wallet"
></q-input>
<br />
</div>
<div class="col-12">
<q-input
dense
@ -124,14 +139,15 @@
></q-input>
</div>
</div>
<div class="row q-mt-lg">
<q-btn label="Topup" color="primary" @click="topupWallet"></q-btn>
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
</div>
</q-form>
</q-card>
</q-dialog>
{% endblock %} {% block scripts %} {{ window_vars(user) }}
<script>
new Vue({
@ -174,7 +190,7 @@
}
],
[
'CLightningWallet',
'CoreLightningWallet',
{
corelightning_rpc: {
value: null,
@ -245,15 +261,15 @@
}
],
[
'LntxbotWallet',
'LnTipsWallet',
{
lntxbot_api_endpoint: {
lntips_api_endpoint: {
value: null,
label: 'Endpoint'
},
lntxbot_key: {
lntips_api_key: {
value: null,
label: 'Key'
label: 'API Key'
}
}
],
@ -279,7 +295,7 @@
{
eclair_url: {
value: null,
label: 'Endpoint'
label: 'URL'
},
eclair_pass: {
value: null,
@ -334,19 +350,6 @@
label: 'Token'
}
}
],
[
'LnTipsWallet',
{
lntips_api_endpoint: {
value: null,
label: 'Endpoint'
},
lntips_api_key: {
value: null,
label: 'API Key'
}
}
]
])
}

View File

@ -48,9 +48,9 @@
<code>{"X-Api-Key": "<i>{{ wallet.inkey }}</i>"}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
<code
>{"out": false, "amount": &lt;int&gt;, "memo": &lt;string&gt;, "unit":
&lt;string&gt;, "webhook": &lt;url:string&gt;, "internal":
&lt;bool&gt;}</code
>{"out": false, "amount": &lt;int&gt;, "memo": &lt;string&gt;,
"expiry": &lt;int&gt;, "unit": &lt;string&gt;, "webhook":
&lt;url:string&gt;, "internal": &lt;bool&gt;}</code
>
<h5 class="text-caption q-mt-sm q-mb-none">
Returns 201 CREATED (application/json)
@ -62,8 +62,7 @@
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code
>curl -X POST {{ request.base_url }}api/v1/payments -d '{"out": false,
"amount": &lt;int&gt;, "memo": &lt;string&gt;, "webhook":
&lt;url:string&gt;, "unit": &lt;string&gt;}' -H "X-Api-Key:
"amount": &lt;int&gt;, "memo": &lt;string&gt;}' -H "X-Api-Key:
<i>{{ wallet.inkey }}</i>" -H "Content-type: application/json"</code
>
</q-card-section>

View File

@ -144,6 +144,7 @@ class CreateInvoiceData(BaseModel):
unit: Optional[str] = "sat"
description_hash: Optional[str] = None
unhashed_description: Optional[str] = None
expiry: Optional[int] = None
lnurl_callback: Optional[str] = None
lnurl_balance_check: Optional[str] = None
extra: Optional[dict] = None
@ -189,6 +190,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet):
memo=memo,
description_hash=description_hash,
unhashed_description=unhashed_description,
expiry=data.expiry,
extra=data.extra,
webhook=data.webhook,
internal=data.internal,

View File

@ -167,6 +167,10 @@ class BoltzExtensionSettings(LNbitsSettings):
boltz_mempool_space_url_ws: str = Field(default="wss://mempool.space")
class LightningSettings(LNbitsSettings):
lightning_invoice_expiry: int = Field(default=600)
class FundingSourcesSettings(
FakeWalletFundingSource,
LNbitsFundingSource,
@ -191,6 +195,7 @@ class EditableSettings(
OpsSettings,
FundingSourcesSettings,
BoltzExtensionSettings,
LightningSettings,
):
@validator(
"lnbits_admin_users",
@ -236,14 +241,14 @@ class SuperUserSettings(LNbitsSettings):
default=[
"VoidWallet",
"FakeWallet",
"CLightningWallet",
"CoreLightningWallet",
"LndRestWallet",
"EclairWallet",
"LndWallet",
"LntxbotWallet",
"LnTipsWallet",
"LNPayWallet",
"LNbitsWallet",
"OpenNodeWallet",
"LnTipsWallet",
]
)
@ -261,7 +266,10 @@ class TransientSettings(InstalledExtensionsSettings):
class ReadOnlySettings(
EnvSettings, SaaSSettings, PersistenceSettings, SuperUserSettings
EnvSettings,
SaaSSettings,
PersistenceSettings,
SuperUserSettings,
):
lnbits_admin_ui: bool = Field(default=False)

View File

@ -48,6 +48,7 @@ class ClicheWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
if unhashed_description or description_hash:
description_hash_str = (

View File

@ -83,6 +83,7 @@ class CoreLightningWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
label = "lbl{}".format(random.random())
msat: int = int(amount * 1000)
@ -103,6 +104,7 @@ class CoreLightningWallet(Wallet):
deschashonly=True
if unhashed_description
else False, # we can't pass None here
expiry=kwargs.get("expiry"),
)
if r.get("code") and r.get("code") < 0:

View File

@ -73,13 +73,17 @@ class EclairWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
data: Dict = {"amountMsat": amount * 1000}
if kwargs.get("expiry"):
data["expireIn"] = kwargs["expiry"]
if description_hash:
data["description_hash"] = description_hash.hex()
data["descriptionHash"] = description_hash.hex()
elif unhashed_description:
data["description_hash"] = hashlib.sha256(unhashed_description).hexdigest()
data["descriptionHash"] = hashlib.sha256(unhashed_description).hexdigest()
else:
data["description"] = memo or ""
@ -162,53 +166,62 @@ class EclairWallet(Wallet):
)
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.url}/getreceivedinfo",
headers=self.auth,
data={"paymentHash": checking_id},
)
data = r.json()
try:
async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.url}/getreceivedinfo",
headers=self.auth,
data={"paymentHash": checking_id},
)
if r.is_error or "error" in data or data.get("status") is None:
r.raise_for_status()
data = r.json()
if r.is_error or "error" in data or data.get("status") is None:
raise Exception("error in eclair response")
statuses = {
"received": True,
"expired": False,
"pending": None,
}
return PaymentStatus(statuses.get(data["status"]["type"]))
except:
return PaymentStatus(None)
statuses = {
"received": True,
"expired": False,
"pending": None,
}
return PaymentStatus(statuses.get(data["status"]["type"]))
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.url}/getsentinfo",
headers=self.auth,
data={"paymentHash": checking_id},
timeout=40,
try:
async with httpx.AsyncClient() as client:
r = await client.post(
f"{self.url}/getsentinfo",
headers=self.auth,
data={"paymentHash": checking_id},
timeout=40,
)
r.raise_for_status()
data = r.json()[-1]
if r.is_error or "error" in data or data.get("status") is None:
raise Exception("error in eclair response")
fee_msat, preimage = None, None
if data["status"]["type"] == "sent":
fee_msat = -data["status"]["feesPaid"]
preimage = data["status"]["paymentPreimage"]
statuses = {
"sent": True,
"failed": False,
"pending": None,
}
return PaymentStatus(
statuses.get(data["status"]["type"]), fee_msat, preimage
)
if r.is_error:
except:
return PaymentStatus(None)
data = r.json()[-1]
if r.is_error or "error" in data or data.get("status") is None:
return PaymentStatus(None)
fee_msat, preimage = None, None
if data["status"]["type"] == "sent":
fee_msat = -data["status"]["feesPaid"]
preimage = data["status"]["paymentPreimage"]
statuses = {
"sent": True,
"failed": False,
"pending": None,
}
return PaymentStatus(statuses.get(data["status"]["type"]), fee_msat, preimage)
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:
try:

View File

@ -41,6 +41,7 @@ class FakeWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
data: Dict = {
"out": False,
@ -54,6 +55,7 @@ class FakeWallet(Wallet):
"expires": None,
"route": None,
}
data["expires"] = kwargs.get("expiry")
data["amount"] = amount * 1000
data["timestamp"] = datetime.now().timestamp()
if description_hash:

View File

@ -59,8 +59,11 @@ class LNbitsWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
data: Dict = {"out": False, "amount": amount}
if kwargs.get("expiry"):
data["expiry"] = kwargs["expiry"]
if description_hash:
data["description_hash"] = description_hash.hex()
if unhashed_description:

View File

@ -154,8 +154,11 @@ class LndWallet(Wallet):
memo: Optional[str] = None,
description_hash: Optional[bytes] = None,
unhashed_description: Optional[bytes] = None,
**kwargs,
) -> InvoiceResponse:
params: Dict = {"value": amount, "expiry": 600, "private": True}
params: Dict = {"value": amount, "private": True}
if kwargs.get("expiry"):
params["expiry"] = kwargs["expiry"]
if description_hash:
params["description_hash"] = description_hash
elif unhashed_description:

View File

@ -77,6 +77,8 @@ class LndRestWallet(Wallet):
**kwargs,
) -> InvoiceResponse:
data: Dict = {"value": amount, "private": True}
if kwargs.get("expiry"):
data["expiry"] = kwargs["expiry"]
if description_hash:
data["description_hash"] = base64.b64encode(description_hash).decode(
"ascii"

View File

@ -119,6 +119,7 @@ class SparkWallet(Wallet):
label=label,
description=memo or "",
exposeprivatechannels=True,
expiry=kwargs.get("expiry"),
)
ok, payment_request, error_message = True, r["bolt11"], ""
except (SparkError, UnknownError) as e:

118
poetry.lock generated
View File

@ -177,14 +177,14 @@ uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "boltz-client"
version = "0.1.2"
version = "0.1.3"
description = "python boltz client"
category = "main"
optional = false
python-versions = ">=3.7,<4.0"
files = [
{file = "boltz_client-0.1.2-py3-none-any.whl", hash = "sha256:2fb0814c7c3ea88d039e71088648df27db0c036b777b0618bd30638dd76ebe90"},
{file = "boltz_client-0.1.2.tar.gz", hash = "sha256:b360c0ff26f2dea62af6457de4d8c46e434cd24b607ed3aa71494409b57e082b"},
{file = "boltz_client-0.1.3-py3-none-any.whl", hash = "sha256:67a231de6cc0876376e32aa177eb572ef14e869a645ef4565f307daa527f1e76"},
{file = "boltz_client-0.1.3.tar.gz", hash = "sha256:1573be84ea547578591d78f5f1ea65ccda01edcca0aa6f077bcd5a497622cef5"},
]
[package.dependencies]
@ -451,63 +451,63 @@ files = [
[[package]]
name = "coverage"
version = "7.0.5"
version = "7.1.0"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"},
{file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"},
{file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"},
{file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"},
{file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"},
{file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"},
{file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"},
{file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"},
{file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"},
{file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"},
{file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"},
{file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"},
{file = "coverage-7.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b69522b168a6b64edf0c33ba53eac491c0a8f5cc94fa4337f9c6f4c8f2f5296c"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436e103950d05b7d7f55e39beeb4d5be298ca3e119e0589c0227e6d0b01ee8c7"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c56bec53d6e3154eaff6ea941226e7bd7cc0d99f9b3756c2520fc7a94e6d96"},
{file = "coverage-7.0.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a38362528a9115a4e276e65eeabf67dcfaf57698e17ae388599568a78dcb029"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f67472c09a0c7486e27f3275f617c964d25e35727af952869dd496b9b5b7f6a3"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:220e3fa77d14c8a507b2d951e463b57a1f7810a6443a26f9b7591ef39047b1b2"},
{file = "coverage-7.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ecb0f73954892f98611e183f50acdc9e21a4653f294dfbe079da73c6378a6f47"},
{file = "coverage-7.0.5-cp37-cp37m-win32.whl", hash = "sha256:d8f3e2e0a1d6777e58e834fd5a04657f66affa615dae61dd67c35d1568c38882"},
{file = "coverage-7.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9e662e6fc4f513b79da5d10a23edd2b87685815b337b1a30cd11307a6679148d"},
{file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"},
{file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"},
{file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"},
{file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"},
{file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"},
{file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"},
{file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"},
{file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"},
{file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"},
{file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"},
{file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"},
{file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"},
{file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"},
{file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"},
{file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"},
{file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"},
{file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"},
{file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"},
{file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"},
{file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"},
{file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"},
{file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"},
{file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"},
{file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"},
{file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"},
{file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"},
{file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"},
{file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"},
{file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"},
{file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"},
{file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"},
{file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"},
{file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"},
{file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"},
{file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"},
{file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"},
{file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"},
{file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"},
{file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"},
{file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"},
{file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"},
{file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"},
{file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"},
{file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"},
{file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"},
{file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"},
{file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"},
{file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"},
{file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"},
{file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"},
{file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"},
{file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"},
{file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"},
{file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"},
{file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"},
{file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"},
{file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"},
{file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"},
{file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"},
{file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"},
{file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"},
{file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"},
{file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"},
{file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"},
{file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"},
]
[package.dependencies]
@ -1156,14 +1156,14 @@ six = "*"
[[package]]
name = "pathspec"
version = "0.10.3"
version = "0.11.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev"
optional = false
python-versions = ">=3.7"
files = [
{file = "pathspec-0.10.3-py3-none-any.whl", hash = "sha256:3c95343af8b756205e2aba76e843ba9520a24dd84f68c22b9f93251507509dd6"},
{file = "pathspec-0.10.3.tar.gz", hash = "sha256:56200de4077d9d0791465aa9095a01d421861e405b5096955051deefd697d6f6"},
{file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"},
{file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"},
]
[[package]]
@ -2112,4 +2112,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "2.0"
python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7"
content-hash = "b2d22a2a33b4c0a4491b5519b28772435c15747b407a150ffa591bcf6ccb56a6"
content-hash = "5d0d9d187fe3c23840fab1d85fca5f0c166e430c4f5d1c1ff636cc621e339eba"

View File

@ -62,8 +62,8 @@ protobuf = "^4.21.6"
Cerberus = "^1.3.4"
async-timeout = "^4.0.2"
pyln-client = "0.11.1"
cashu = "^0.8.2"
boltz-client = "^0.1.2"
cashu = "0.8.2"
boltz-client = "0.1.3"
[tool.poetry.dev-dependencies]

View File

@ -94,6 +94,21 @@ async def test_create_internal_invoice(client, inkey_headers_to):
return invoice
# check POST /api/v1/payments: invoice with custom expiry
@pytest.mark.asyncio
async def test_create_invoice_custom_expiry(client, inkey_headers_to):
data = await get_random_invoice_data()
expiry_seconds = 600 * 6 * 24 * 31 # 31 days in the future
data["expiry"] = expiry_seconds
response = await client.post(
"/api/v1/payments", json=data, headers=inkey_headers_to
)
assert response.status_code == 201
invoice = response.json()
bolt11_invoice = bolt11.decode(invoice["payment_request"])
assert bolt11_invoice.expiry == expiry_seconds
# check POST /api/v1/payments: make payment
@pytest.mark.asyncio
async def test_pay_invoice(client, invoice, adminkey_headers_from):

View File

@ -0,0 +1,80 @@
# Python script to create a fake admin user for sqlite3,
# for regtest setup as LNbits funding source
import os
import sqlite3
import sys
import time
from uuid import uuid4
import shortuuid
adminkey = "d08a3313322a4514af75d488bcc27eee"
sqfolder = "./data"
if not sqfolder or not os.path.isdir(sqfolder):
print("missing LNBITS_DATA_FOLDER")
sys.exit(1)
file = os.path.join(sqfolder, "database.sqlite3")
conn = sqlite3.connect(file)
cursor = conn.cursor()
old_account = cursor.execute(
"SELECT * FROM accounts WHERE id = ?", (adminkey,)
).fetchone()
if old_account:
print("fake admin does already exist")
sys.exit(1)
cursor.execute("INSERT INTO accounts (id) VALUES (?)", (adminkey,))
wallet_id = uuid4().hex
cursor.execute(
"""
INSERT INTO wallets (id, name, "user", adminkey, inkey)
VALUES (?, ?, ?, ?, ?)
""",
(
wallet_id,
"TEST WALLET",
adminkey,
adminkey,
uuid4().hex, # invoice key is not important
),
)
expiration_date = time.time() + 420
# 1 btc in sats
amount = 100_000_000
internal_id = f"internal_{shortuuid.uuid()}"
cursor.execute(
"""
INSERT INTO apipayments
(wallet, checking_id, bolt11, hash, preimage,
amount, pending, memo, fee, extra, webhook, expiry)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
wallet_id,
internal_id,
"test_admin_internal",
"test_admin_internal",
None,
amount * 1000,
False,
"test_admin_internal",
0,
None,
"",
expiration_date,
),
)
print(f"created test admin: {adminkey} with {amount} sats")
conn.commit()
cursor.close()