From 6e405d1fc4073b34d880f6045c5c7ec3f2f7ccf0 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 21 Sep 2022 17:13:05 +0300 Subject: [PATCH 01/20] fix: output address on confirmation based on selected network --- lnbits/extensions/watchonly/models.py | 1 + .../watchonly/static/components/payment/payment.js | 6 ++++-- lnbits/extensions/watchonly/templates/watchonly/index.html | 1 + lnbits/extensions/watchonly/views_api.py | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py index cedaa210..622f5ec8 100644 --- a/lnbits/extensions/watchonly/models.py +++ b/lnbits/extensions/watchonly/models.py @@ -80,6 +80,7 @@ class CreatePsbt(BaseModel): class ExtractPsbt(BaseModel): psbtBase64 = "" # // todo snake case inputs: List[TransactionInput] + network = "Mainnet" class SignedTransaction(BaseModel): diff --git a/lnbits/extensions/watchonly/static/components/payment/payment.js b/lnbits/extensions/watchonly/static/components/payment/payment.js index f2cccbba..9f38df1d 100644 --- a/lnbits/extensions/watchonly/static/components/payment/payment.js +++ b/lnbits/extensions/watchonly/static/components/payment/payment.js @@ -11,7 +11,8 @@ async function payment(path) { 'mempool-endpoint', 'sats-denominated', 'serial-signer-ref', - 'adminkey' + 'adminkey', + 'network' ], watch: { immediate: true, @@ -279,7 +280,8 @@ async function payment(path) { this.adminkey, { psbtBase64, - inputs: this.tx.inputs + inputs: this.tx.inputs, + network: this.network } ) return data diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html index 263f6d92..91577cd2 100644 --- a/lnbits/extensions/watchonly/templates/watchonly/index.html +++ b/lnbits/extensions/watchonly/templates/watchonly/index.html @@ -136,6 +136,7 @@ :adminkey="g.user.wallets[0].adminkey" :serial-signer-ref="$refs.serialSigner" :sats-denominated="config.sats_denominated" + :network="config.network" @broadcast-done="handleBroadcastSuccess" > diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py index 77d28fee..750d46c9 100644 --- a/lnbits/extensions/watchonly/views_api.py +++ b/lnbits/extensions/watchonly/views_api.py @@ -4,6 +4,7 @@ from http import HTTPStatus import httpx from embit import finalizer, script from embit.ec import PublicKey +from embit.networks import NETWORKS from embit.psbt import PSBT, DerivationPath from embit.transaction import Transaction, TransactionInput, TransactionOutput from fastapi import Query, Request @@ -295,6 +296,7 @@ async def api_psbt_create( async def api_psbt_extract_tx( data: ExtractPsbt, w: WalletTypeInfo = Depends(require_admin_key) ): + network = NETWORKS["main"] if data.network == "Mainnet" else NETWORKS["test"] res = SignedTransaction() try: psbt = PSBT.from_base64(data.psbtBase64) @@ -316,7 +318,7 @@ async def api_psbt_extract_tx( for out in transaction.vout: tx["outputs"].append( - {"amount": out.value, "address": out.script_pubkey.address()} + {"amount": out.value, "address": out.script_pubkey.address(network)} ) res.tx_json = json.dumps(tx) except Exception as e: From 80a62569f9164c8fffe6ec33a04df38234dd44d1 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 22 Sep 2022 10:41:54 +0300 Subject: [PATCH 02/20] fix: wait for connection to init --- .../components/serial-signer/serial-signer.js | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js index 33d07d94..33261280 100644 --- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js +++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js @@ -15,7 +15,7 @@ async function serialSigner(path) { receivedData: '', config: {}, decryptionKey: null, - sharedSecret: null, // todo: store in secure local storage + sharedSecret: null, hww: { password: null, @@ -57,13 +57,16 @@ async function serialSigner(path) { computed: { pairedDevices: { + cache: false, get: function () { + console.log('### get pairedDevices') return ( JSON.parse(window.localStorage.getItem('lnbits-paired-devices')) || [] ) }, set: function (devices) { + console.log('### set pairedDevices', devices) window.localStorage.setItem( 'lnbits-paired-devices', JSON.stringify(devices) @@ -81,6 +84,7 @@ async function serialSigner(path) { await this.openSerialPort(this.config) }, openSerialPort: async function (config = {baudRate: 9600}) { + console.log('### openSerialPort', config) if (!this.checkSerialPortSupported()) return false if (this.selectedPort) { this.$q.notify({ @@ -109,7 +113,10 @@ async function serialSigner(path) { // Wait for the serial port to open. await this.selectedPort.open(config) + // do not await this.startSerialPortReading() + // wait to init + sleep(1000) const textEncoder = new TextEncoderStream() this.writableStreamClosed = textEncoder.readable.pipeTo( @@ -307,7 +314,11 @@ async function serialSigner(path) { }, hwwPing: async function () { try { + console.log('### hwwPing 1', window.location.host) + // Send an empty ping. The serial port buffer might have some jubk data. Flush it. + await this.sendCommandClearText(COMMAND_PING) await this.sendCommandClearText(COMMAND_PING, [window.location.host]) + console.log('### hwwPing 2') } catch (error) { this.$q.notify({ type: 'warning', @@ -582,7 +593,7 @@ async function serialSigner(path) { hwwCheckPairing: async function () { const iv = window.crypto.getRandomValues(new Uint8Array(16)) const encrypted = await this.encryptMessage( - this.sharedSecret, + this.sharedSecret, // todo: revisit iv, PAIRING_CONTROL_TEXT.length + ' ' + PAIRING_CONTROL_TEXT ) @@ -724,6 +735,7 @@ async function serialSigner(path) { }, hwwHelp: async function () { try { + console.log('### cmd help') await this.sendCommandSecure(COMMAND_HELP) this.$q.notify({ type: 'positive', @@ -746,7 +758,7 @@ async function serialSigner(path) { } catch (error) { this.$q.notify({ type: 'warning', - message: 'Failed to ask for help!', + message: 'Failed to wipe!', caption: `${error}`, timeout: 10000 }) @@ -861,7 +873,13 @@ async function serialSigner(path) { sendCommandSecure: async function (command, attrs = []) { const message = [command].concat(attrs).join(' ') + console.log('### sendCommandSecure', message) const iv = window.crypto.getRandomValues(new Uint8Array(16)) + if (!this.sharedSecret || !this.sharedSecret.length) { + throw new Error( + `Secure connection not estabileshed. Tried to run command: ${command}` + ) + } const encrypted = await this.encryptMessage( this.sharedSecret, iv, @@ -874,6 +892,7 @@ async function serialSigner(path) { }, sendCommandClearText: async function (command, attrs = []) { const message = [command].concat(attrs).join(' ') + console.log('### sendCommandClearText', message) await this.writer.write(message + '\n') }, extractCommand: async function (value) { From d5f78e83d927c61071a709175a95692e06188c49 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 22 Sep 2022 10:42:27 +0300 Subject: [PATCH 03/20] chore: update `created by` --- .../watchonly/templates/watchonly/_api_docs.html | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html b/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html index ba52c4fa..e40ca81f 100644 --- a/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html +++ b/lnbits/extensions/watchonly/templates/watchonly/_api_docs.html @@ -18,9 +18,21 @@ >directly from browser -
Created by, +
Created by Ben Arc, + Tiago Vasconcelos, + motorina0 (using, Date: Thu, 22 Sep 2022 10:58:19 +0300 Subject: [PATCH 04/20] fix: paired devices list --- .../serial-signer/serial-signer.html | 2 +- .../components/serial-signer/serial-signer.js | 21 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html index 2ed2d49c..a95a1906 100644 --- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html +++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.html @@ -49,7 +49,7 @@ diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js index 33261280..b27f2fa2 100644 --- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js +++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js @@ -51,7 +51,8 @@ async function serialSigner(path) { }, tx: null, // todo: move to hww - showConsole: false + showConsole: false, + showPairedDevices: true } }, @@ -59,14 +60,12 @@ async function serialSigner(path) { pairedDevices: { cache: false, get: function () { - console.log('### get pairedDevices') return ( JSON.parse(window.localStorage.getItem('lnbits-paired-devices')) || [] ) }, set: function (devices) { - console.log('### set pairedDevices', devices) window.localStorage.setItem( 'lnbits-paired-devices', JSON.stringify(devices) @@ -84,7 +83,6 @@ async function serialSigner(path) { await this.openSerialPort(this.config) }, openSerialPort: async function (config = {baudRate: 9600}) { - console.log('### openSerialPort', config) if (!this.checkSerialPortSupported()) return false if (this.selectedPort) { this.$q.notify({ @@ -314,11 +312,9 @@ async function serialSigner(path) { }, hwwPing: async function () { try { - console.log('### hwwPing 1', window.location.host) // Send an empty ping. The serial port buffer might have some jubk data. Flush it. await this.sendCommandClearText(COMMAND_PING) await this.sendCommandClearText(COMMAND_PING, [window.location.host]) - console.log('### hwwPing 2') } catch (error) { this.$q.notify({ type: 'warning', @@ -735,7 +731,6 @@ async function serialSigner(path) { }, hwwHelp: async function () { try { - console.log('### cmd help') await this.sendCommandSecure(COMMAND_HELP) this.$q.notify({ type: 'positive', @@ -873,7 +868,6 @@ async function serialSigner(path) { sendCommandSecure: async function (command, attrs = []) { const message = [command].concat(attrs).join(' ') - console.log('### sendCommandSecure', message) const iv = window.crypto.getRandomValues(new Uint8Array(16)) if (!this.sharedSecret || !this.sharedSecret.length) { throw new Error( @@ -892,7 +886,6 @@ async function serialSigner(path) { }, sendCommandClearText: async function (command, attrs = []) { const message = [command].concat(attrs).join(' ') - console.log('### sendCommandClearText', message) await this.writer.write(message + '\n') }, extractCommand: async function (value) { @@ -968,6 +961,11 @@ async function serialSigner(path) { devices.splice(deviceIndex, 1) } this.pairedDevices = devices + this.showPairedDevices = false + setTimeout(() => { + // force UI refresh + this.showPairedDevices = true + }) }, addPairedDevice: function (deviceId, sharedSecretHex, config) { const devices = this.pairedDevices @@ -979,6 +977,11 @@ async function serialSigner(path) { config }) this.pairedDevices = devices + this.showPairedDevices = false + setTimeout(() => { + // force UI refresh + this.showPairedDevices = true + }) }, updatePairedDeviceConfig(deviceId, config) { const device = this.getPairedDevice(deviceId) From 649c653836502a9cc29ec468874e2f9d3860a305 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 27 Sep 2022 17:19:32 +0300 Subject: [PATCH 05/20] fix: do not show command data in logs --- .../static/components/serial-signer/serial-signer.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js index b27f2fa2..67268eeb 100644 --- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js +++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js @@ -230,8 +230,9 @@ async function serialSigner(path) { while (true) { const {value, done} = await readStringUntil('\n') if (value) { - this.handleSerialPortResponse(value) - this.updateSerialPortConsole(value) + const {command, commandData} = await this.extractCommand(value) + this.handleSerialPortResponse(command, commandData) + this.updateSerialPortConsole(command) } if (done) return } @@ -245,8 +246,7 @@ async function serialSigner(path) { } } }, - handleSerialPortResponse: async function (value) { - const {command, commandData} = await this.extractCommand(value) + handleSerialPortResponse: async function (command, commandData) { this.logPublicCommandsResponse(command, commandData) switch (command) { @@ -287,7 +287,7 @@ async function serialSigner(path) { ) break default: - console.log(` %c${value}`, 'background: #222; color: red') + console.log(` %c${command}`, 'background: #222; color: red') } }, logPublicCommandsResponse: function (command, commandData) { From f1670c3153d990aea8060b5305bc0861d2712573 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 27 Sep 2022 17:20:33 +0300 Subject: [PATCH 06/20] chore: version bump --- lnbits/extensions/watchonly/templates/watchonly/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/watchonly/templates/watchonly/index.html b/lnbits/extensions/watchonly/templates/watchonly/index.html index 91577cd2..67f89810 100644 --- a/lnbits/extensions/watchonly/templates/watchonly/index.html +++ b/lnbits/extensions/watchonly/templates/watchonly/index.html @@ -150,7 +150,7 @@
{{SITE_TITLE}} Onchain Wallet (watch-only) Extension - (v0.2) + (v0.3)
From a8b90bd5952601577f6aa5b4c9ff8e4b499d361c Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 27 Sep 2022 17:35:27 +0300 Subject: [PATCH 07/20] fix: close serial port when re-pairing fails --- .../components/serial-signer/serial-signer.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js index 67268eeb..8d3c1fec 100644 --- a/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js +++ b/lnbits/extensions/watchonly/static/components/serial-signer/serial-signer.js @@ -610,10 +610,10 @@ async function serialSigner(path) { } }, handleCheckPairingResponse: async function (res = '') { - const [statusCode, encryptedMessage] = res.split(' ') + const [statusCode, message] = res.split(' ') switch (statusCode) { case '0': - const controlText = await this.decryptData(encryptedMessage) + const controlText = await this.decryptData(message) if (controlText == PAIRING_CONTROL_TEXT) { this.$q.notify({ type: 'positive', @@ -629,6 +629,16 @@ async function serialSigner(path) { }) } break + case '1': + this.closeSerialPort() + this.$q.notify({ + type: 'warning', + message: + 'Re-pairing failed. Remove (forget) device and try again!', + caption: `Error: ${message}`, + timeout: 10000 + }) + break default: // noting to do here yet break From 19b1374d51ffe333c1862e8dbcb8332704f5b8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 27 Sep 2022 17:44:52 +0200 Subject: [PATCH 08/20] fixing tests for new poetry version ^1.2 --- .github/workflows/formatting.yml | 13 ++++++++++++- .github/workflows/migrations.yml | 8 ++++++-- .github/workflows/mypy.yml | 8 ++++++-- .github/workflows/regtest.yml | 24 ++++++++++++++++++------ .github/workflows/tests.yml | 19 ++++++++++++++----- 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index e106ace3..e3d0fd35 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -9,9 +9,20 @@ on: jobs: checks: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - - uses: abatilo/actions-poetry@v2.1.3 + - 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: Install packages run: poetry install - name: Check black diff --git a/.github/workflows/migrations.yml b/.github/workflows/migrations.yml index 90006d2a..c280ad7d 100644 --- a/.github/workflows/migrations.yml +++ b/.github/workflows/migrations.yml @@ -22,14 +22,18 @@ jobs: --health-retries 5 strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - name: Set up Poetry ${{ matrix.poetry-version }} + uses: abatilo/actions-poetry@v2 + with: + poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies run: | poetry install diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 61601731..d80da678 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -7,14 +7,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - name: Set up Poetry ${{ matrix.poetry-version }} + uses: abatilo/actions-poetry@v2 + with: + poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies run: | poetry install diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml index 6572ccdb..2d7aae6b 100644 --- a/.github/workflows/regtest.yml +++ b/.github/workflows/regtest.yml @@ -7,14 +7,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - 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 . @@ -46,14 +50,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - 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 . @@ -86,14 +94,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - 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 . diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 298d7ff0..5d368fbb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,8 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} @@ -29,14 +30,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - name: Set up Poetry ${{ matrix.poetry-version }} + uses: abatilo/actions-poetry@v2 + with: + poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies env: VIRTUAL_ENV: ./venv @@ -64,14 +69,18 @@ jobs: --health-retries 5 strategy: matrix: - python-version: [3.9] + python-version: ["3.9"] + poetry-version: ["1.2.1"] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - uses: abatilo/actions-poetry@v2.1.3 + - name: Set up Poetry ${{ matrix.poetry-version }} + uses: abatilo/actions-poetry@v2 + with: + poetry-version: ${{ matrix.poetry-version }} - name: Install dependencies run: | poetry install From 463941ec94cee61814a3f0714f2a76247175a6bc Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 28 Sep 2022 10:33:43 +0300 Subject: [PATCH 09/20] fix: always include change output for fee --- .../extensions/watchonly/static/components/payment/payment.html | 2 +- .../watchonly/static/components/serial-signer/serial-signer.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/watchonly/static/components/payment/payment.html b/lnbits/extensions/watchonly/static/components/payment/payment.html index cde65ca2..6e1d94c7 100644 --- a/lnbits/extensions/watchonly/static/components/payment/payment.html +++ b/lnbits/extensions/watchonly/static/components/payment/payment.html @@ -5,7 +5,7 @@ Date: Thu, 29 Sep 2022 10:31:10 +0100 Subject: [PATCH 10/20] Added Caddy --- docs/guide/installation.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 2b058754..e77e301d 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -292,6 +292,41 @@ Save the file and run the following commands: sudo systemctl enable lnbits.service sudo systemctl start lnbits.service ``` +## Running using Caddy reverse proxy with automatic https + +Point your domain at the IP of the server you're running LNbits on, by making an `A` record. + +Install Caddy on the server +https://caddyserver.com/docs/install#debian-ubuntu-raspbian + +``` +sudo caddy stop +``` +Create a Caddyfile +``` +sudo nano Caddyfile +``` +Assuming your LNbits is running on port `5000`: +``` +yourdomain.com { + handle /api/v1/payments/sse* { + reverse_proxy 0.0.0.0:5000 { + header_up X-Forwarded-Host legend.lnbits.com + transport http { + keepalive off + compression off + } + } + } + reverse_proxy 0.0.0.0:5000 { + header_up X-Forwarded-Host legend.lnbits.com + } +} +``` +Save and exit `CTRL + x` +``` +sudo caddy start +``` ## Running behind an apache2 reverse proxy over https Install apache2 and enable apache2 mods From 55b0814d932bda58545ba25cf95f5cac02477039 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 29 Sep 2022 10:34:03 +0100 Subject: [PATCH 11/20] added intro --- docs/guide/installation.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index e77e301d..21ee307a 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -292,7 +292,9 @@ Save the file and run the following commands: sudo systemctl enable lnbits.service sudo systemctl start lnbits.service ``` -## Running using Caddy reverse proxy with automatic https +## Setting up a Caddy reverse proxy with automatic https + +USe Caddy to easily make your LNbits install accessible over clearnet with a domain and https cert. Point your domain at the IP of the server you're running LNbits on, by making an `A` record. From 7de17485d39e262f81e0dfd0cbc61b22cab3f1dc Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 29 Sep 2022 10:34:53 +0100 Subject: [PATCH 12/20] typo --- docs/guide/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 21ee307a..d79363af 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -294,7 +294,7 @@ sudo systemctl start lnbits.service ``` ## Setting up a Caddy reverse proxy with automatic https -USe Caddy to easily make your LNbits install accessible over clearnet with a domain and https cert. +Use Caddy to make your LNbits install accessible over clearnet with a domain and https cert. Point your domain at the IP of the server you're running LNbits on, by making an `A` record. From 9c575b7d3a46f355ec01dad4b27de70b9be4c440 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 29 Sep 2022 10:37:16 +0100 Subject: [PATCH 13/20] typo --- docs/guide/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index d79363af..7f2aefdc 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -292,7 +292,7 @@ Save the file and run the following commands: sudo systemctl enable lnbits.service sudo systemctl start lnbits.service ``` -## Setting up a Caddy reverse proxy with automatic https +## Reverse proxy with automatic https using Caddy Use Caddy to make your LNbits install accessible over clearnet with a domain and https cert. @@ -308,7 +308,7 @@ Create a Caddyfile ``` sudo nano Caddyfile ``` -Assuming your LNbits is running on port `5000`: +Assuming your LNbits is running on port `5000` add: ``` yourdomain.com { handle /api/v1/payments/sse* { From 07293e7d5ce765807f753c7ef0f0e6723f95f4a4 Mon Sep 17 00:00:00 2001 From: Arc <33088785+arcbtc@users.noreply.github.com> Date: Thu, 29 Sep 2022 10:45:09 +0100 Subject: [PATCH 14/20] Update installation.md --- docs/guide/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 7f2aefdc..87679ed5 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -313,7 +313,7 @@ Assuming your LNbits is running on port `5000` add: yourdomain.com { handle /api/v1/payments/sse* { reverse_proxy 0.0.0.0:5000 { - header_up X-Forwarded-Host legend.lnbits.com + header_up X-Forwarded-Host yourdomain.com transport http { keepalive off compression off @@ -321,7 +321,7 @@ yourdomain.com { } } reverse_proxy 0.0.0.0:5000 { - header_up X-Forwarded-Host legend.lnbits.com + header_up X-Forwarded-Host yourdomain.com } } ``` From 325139066c309d4080ab7c2e94ad01ede63cdba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 29 Sep 2022 20:40:58 +0200 Subject: [PATCH 15/20] fix service-worker.js issue #1009 (#1017) * service-worker.js fix for issue #1009 fixup * remove weird comment --- lnbits/core/static/js/service-worker.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lnbits/core/static/js/service-worker.js b/lnbits/core/static/js/service-worker.js index 041b9f32..98ae497e 100644 --- a/lnbits/core/static/js/service-worker.js +++ b/lnbits/core/static/js/service-worker.js @@ -3,7 +3,11 @@ const CACHE_VERSION = 1 const CURRENT_CACHE = `lnbits-${CACHE_VERSION}-` const getApiKey = request => { - return request.headers.get('X-Api-Key') || 'none' + let api_key = request.headers.get('X-Api-Key') + if (!api_key || api_key == 'undefined') { + api_key = 'no_api_key' + } + return api_key } // on activation we clean up the previously registered service workers @@ -26,8 +30,10 @@ self.addEventListener('activate', evt => // If no response is found, it populates the runtime cache with the response // from the network before returning it to the page. self.addEventListener('fetch', event => { - // Skip cross-origin requests, like those for Google Analytics. if ( + !event.request.url.startsWith( + self.location.origin + '/api/v1/payments/sse' + ) && event.request.url.startsWith(self.location.origin) && event.request.method == 'GET' ) { From b2a26b0a7abf5cc2b8d855bcefb02c44e4db4e2a Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Fri, 30 Sep 2022 12:41:35 +0100 Subject: [PATCH 16/20] add small description in UI (#1023) --- .../extensions/scrub/templates/scrub/index.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lnbits/extensions/scrub/templates/scrub/index.html b/lnbits/extensions/scrub/templates/scrub/index.html index c063c858..5a1cae58 100644 --- a/lnbits/extensions/scrub/templates/scrub/index.html +++ b/lnbits/extensions/scrub/templates/scrub/index.html @@ -68,6 +68,21 @@
{{SITE_TITLE}} Scrub extension
+

+ Automatically forward funds (Scrub) that get paid to the LNbits + wallet, to an LNURLpay or Lightning Address. +
+ More info in Scrub's +
readme. +

+

+ Important: wallet will need a float to account for + any fees, before being able to push a payment +

From 4ad3c841528de3efafefe48f667e6800eb7074e3 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 30 Sep 2022 13:55:46 +0200 Subject: [PATCH 17/20] downgrade pyln from 0.12.0 to 0.11.1 (#1021) --- poetry.lock | 36 ++++++++++++++++++++++++++++-------- pyproject.toml | 2 +- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/poetry.lock b/poetry.lock index ea83e25e..2a57a5c1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -118,6 +118,9 @@ category = "main" optional = false python-versions = ">=2.7" +[package.dependencies] +setuptools = "*" + [[package]] name = "certifi" version = "2021.5.30" @@ -206,7 +209,7 @@ python-versions = ">=3.6" cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx_rtd_theme"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] sdist = ["setuptools_rust (>=0.11.4)"] @@ -638,7 +641,7 @@ python-versions = ">=3.7,<4.0" [[package]] name = "pyln-client" -version = "0.12.0.post1" +version = "0.11.1" description = "Client library and plugin library for Core Lightning" category = "main" optional = false @@ -707,7 +710,7 @@ pathlib2 = "*" six = "*" [[package]] -name = "pysocks" +name = "PySocks" version = "1.7.1" description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." category = "main" @@ -823,6 +826,19 @@ python-versions = "*" [package.dependencies] cffi = ">=1.3.0" +[[package]] +name = "setuptools" +version = "65.4.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "shortuuid" version = "1.0.1" @@ -860,7 +876,7 @@ mssql = ["pyodbc"] mssql_pymssql = ["pymssql"] mssql_pyodbc = ["pyodbc"] mysql = ["mysqlclient"] -oracle = ["cx-oracle"] +oracle = ["cx_oracle"] postgresql = ["psycopg2"] postgresql_pg8000 = ["pg8000 (<1.16.6)"] postgresql_psycopg2binary = ["psycopg2-binary"] @@ -1024,7 +1040,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black ( [metadata] lock-version = "1.1" python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7" -content-hash = "d0556d4a307864ba04a1e5da517884e523396c98a00ae09d9192c37b1d2c555b" +content-hash = "72e4462285d0bc5e2cb83c88c613726beced959b268bd30b984d8baaeff178ea" [metadata.files] aiofiles = [ @@ -1661,8 +1677,8 @@ pyln-bolt7 = [ {file = "pyln_bolt7-1.0.246-py3-none-any.whl", hash = "sha256:54d48ec27fdc8751762cb068b0a9f2757a58fb57933c6d8f8255d02c27eb63c5"}, ] pyln-client = [ - {file = "pyln-client-0.12.0.post1.tar.gz", hash = "sha256:c80338e8e9f435720c0e5f552dc4016fc8fba16d4b79764f881067e0fcd5d5c7"}, - {file = "pyln_client-0.12.0.post1-py3-none-any.whl", hash = "sha256:cfe3404eb88f294015145e668d774dd754b3baec36b44fe773fa354f1e1e48c1"}, + {file = "pyln-client-0.11.1.tar.gz", hash = "sha256:f5ea648840b030e2bbcf8c66ee72d25a5817f89854434a28d30e887547138c8e"}, + {file = "pyln_client-0.11.1-py3-none-any.whl", hash = "sha256:497db443406b80c98c0434e2938eb1b2a17e88fd9aa63b018124068198df6141"}, ] pyln-proto = [ {file = "pyln-proto-0.11.1.tar.gz", hash = "sha256:9bed240f41917c4fd526b767218a77d0fbe69242876eef72c35a856796f922d6"}, @@ -1682,7 +1698,7 @@ pyqrcode = [ pyscss = [ {file = "pyScss-1.4.0.tar.gz", hash = "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff"}, ] -pysocks = [ +PySocks = [ {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, @@ -1767,6 +1783,10 @@ secp256k1 = [ {file = "secp256k1-0.14.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9e7c024ff17e9b9d7c392bb2a917da231d6cb40ab119389ff1f51dca10339a4"}, {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, ] +setuptools = [ + {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, + {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, +] shortuuid = [ {file = "shortuuid-1.0.1-py3-none-any.whl", hash = "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77"}, {file = "shortuuid-1.0.1.tar.gz", hash = "sha256:3c11d2007b915c43bee3e10625f068d8a349e04f0d81f08f5fa08507427ebf1f"}, diff --git a/pyproject.toml b/pyproject.toml index 7f833aa5..864500f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,7 +62,7 @@ cffi = "1.15.0" websocket-client = "1.3.3" grpcio = "^1.49.1" protobuf = "^4.21.6" -pyln-client = "^0.12.0" +pyln-client = "0.11.1" [tool.poetry.dev-dependencies] isort = "^5.10.1" From 41668d6f3288fa75ac47be685e338242e0ec85c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 1 Oct 2022 11:33:58 +0200 Subject: [PATCH 18/20] add warning for voidwallet for better coloring in logs --- lnbits/wallets/void.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/wallets/void.py b/lnbits/wallets/void.py index 0de387aa..b74eb245 100644 --- a/lnbits/wallets/void.py +++ b/lnbits/wallets/void.py @@ -23,7 +23,7 @@ class VoidWallet(Wallet): raise Unsupported("") async def status(self) -> StatusResponse: - logger.info( + logger.warning( "This backend does nothing, it is here just as a placeholder, you must configure an actual backend before being able to do anything useful with LNbits." ) return StatusResponse(None, 0) From 5a12f4f237a1a292c394a8bfeb3d5d40577afac7 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:51:47 +0200 Subject: [PATCH 19/20] Improved SSE listeners (#865) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * logging listeners * comments * generate privkey upon init * listener queue * remove duplicate check * make format * reuse channel * error handling in sse listener * uuid for listeners * register named invoices * uuid for listeners and listener list * fix poetry lock * setuptools * requirements asyncio timeout * setuptool;s * make format * remove async-timeout * async_timeout readd * try lower setuptools version * try lower lower setuptools version * back to current version + fix, maybe * fix worflows to use poetry 1.2.1 * remove uneeded setuptools from build-system * fix up formatting workflow * debug to trace * more traces * debug logs to trace Co-authored-by: dni ⚡ --- lnbits/app.py | 3 +- lnbits/core/services.py | 2 +- lnbits/core/tasks.py | 40 ++++++++--- lnbits/core/views/api.py | 45 ++++++++----- lnbits/core/views/public_api.py | 4 +- lnbits/extensions/boltcards/tasks.py | 3 +- lnbits/extensions/boltz/boltz.py | 4 +- lnbits/extensions/boltz/mempool.py | 4 +- lnbits/extensions/boltz/tasks.py | 3 +- lnbits/extensions/copilot/tasks.py | 3 +- lnbits/extensions/jukebox/tasks.py | 3 +- lnbits/extensions/livestream/tasks.py | 4 +- lnbits/extensions/lnaddress/tasks.py | 3 +- lnbits/extensions/lnticket/__init__.py | 1 + lnbits/extensions/lnticket/tasks.py | 3 +- lnbits/extensions/lnurlp/tasks.py | 3 +- lnbits/extensions/lnurlpayout/tasks.py | 3 +- lnbits/extensions/satspay/tasks.py | 3 +- lnbits/extensions/scrub/tasks.py | 3 +- lnbits/extensions/splitpayments/tasks.py | 4 +- lnbits/extensions/subdomains/tasks.py | 3 +- lnbits/extensions/tpos/tasks.py | 4 +- lnbits/helpers.py | 23 +++++++ lnbits/tasks.py | 84 +++++++++++++++++------- lnbits/wallets/fake.py | 32 ++++----- poetry.lock | 57 ++++++++++------ pyproject.toml | 3 +- requirements.txt | 2 + 28 files changed, 239 insertions(+), 110 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index f612c32c..51482538 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -34,7 +34,6 @@ from .tasks import ( check_pending_payments, internal_invoice_listener, invoice_listener, - run_deferred_async, webhook_handler, ) @@ -185,7 +184,7 @@ def register_async_tasks(app): loop.create_task(catch_everything_and_restart(invoice_listener)) loop.create_task(catch_everything_and_restart(internal_invoice_listener)) await register_task_listeners() - await run_deferred_async() + # await run_deferred_async() # calle: doesn't do anyting? @app.on_event("shutdown") async def stop_listeners(): diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 961eb7b2..5d993b4c 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -186,9 +186,9 @@ async def pay_invoice( ) # notify receiver asynchronously - from lnbits.tasks import internal_invoice_queue + logger.debug(f"enqueuing internal invoice {internal_checking_id}") await internal_invoice_queue.put(internal_checking_id) else: logger.debug(f"backend: sending payment {temp_id}") diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index 07b8a893..b57e2625 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -1,30 +1,43 @@ import asyncio -from typing import List +from typing import Dict import httpx from loguru import logger -from lnbits.tasks import register_invoice_listener +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import SseListenersDict, register_invoice_listener from . import db from .crud import get_balance_notify from .models import Payment -api_invoice_listeners: List[asyncio.Queue] = [] +api_invoice_listeners: Dict[str, asyncio.Queue] = SseListenersDict( + "api_invoice_listeners" +) async def register_task_listeners(): + """ + Registers an invoice listener queue for the core tasks. + Incoming payaments in this queue will eventually trigger the signals sent to all other extensions + and fulfill other core tasks such as dispatching webhooks. + """ invoice_paid_queue = asyncio.Queue(5) - register_invoice_listener(invoice_paid_queue) + # we register invoice_paid_queue to receive all incoming invoices + register_invoice_listener(invoice_paid_queue, "core/tasks.py") + # register a worker that will react to invoices asyncio.create_task(wait_for_paid_invoices(invoice_paid_queue)) async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue): + """ + This worker dispatches events to all extensions, dispatches webhooks and balance notifys. + """ while True: payment = await invoice_paid_queue.get() - logger.debug("received invoice paid event") + logger.trace("received invoice paid event") # send information to sse channel - await dispatch_invoice_listener(payment) + await dispatch_api_invoice_listeners(payment) # dispatch webhook if payment.webhook and not payment.webhook_status: @@ -41,16 +54,23 @@ async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue): pass -async def dispatch_invoice_listener(payment: Payment): - for send_channel in api_invoice_listeners: +async def dispatch_api_invoice_listeners(payment: Payment): + """ + Emits events to invoice listener subscribed from the API. + """ + for chan_name, send_channel in api_invoice_listeners.items(): try: + logger.debug(f"sending invoice paid event to {chan_name}") send_channel.put_nowait(payment) except asyncio.QueueFull: - logger.debug("removing sse listener", send_channel) - api_invoice_listeners.remove(send_channel) + logger.error(f"removing sse listener {send_channel}:{chan_name}") + api_invoice_listeners.pop(chan_name) async def dispatch_webhook(payment: Payment): + """ + Dispatches the webhook to the webhook url. + """ async with httpx.AsyncClient() as client: data = payment.dict() try: diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 7a2bbbe6..c07df568 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -3,11 +3,13 @@ import binascii import hashlib import json import time +import uuid from http import HTTPStatus from io import BytesIO from typing import Dict, List, Optional, Tuple, Union from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse +import async_timeout import httpx import pyqrcode from fastapi import Depends, Header, Query, Request @@ -16,7 +18,7 @@ from fastapi.params import Body from loguru import logger from pydantic import BaseModel from pydantic.fields import Field -from sse_starlette.sse import EventSourceResponse +from sse_starlette.sse import EventSourceResponse, ServerSentEvent from starlette.responses import HTMLResponse, StreamingResponse from lnbits import bolt11, lnurl @@ -366,37 +368,48 @@ async def api_payments_pay_lnurl( } -async def subscribe(request: Request, wallet: Wallet): +async def subscribe_wallet_invoices(request: Request, wallet: Wallet): + """ + Subscribe to new invoices for a wallet. Can be wrapped in EventSourceResponse. + Listenes invoming payments for a wallet and yields jsons with payment details. + """ this_wallet_id = wallet.id payment_queue: asyncio.Queue[Payment] = asyncio.Queue(0) - logger.debug("adding sse listener", payment_queue) - api_invoice_listeners.append(payment_queue) + uid = f"{this_wallet_id}_{str(uuid.uuid4())[:8]}" + logger.debug(f"adding sse listener for wallet: {uid}") + api_invoice_listeners[uid] = payment_queue send_queue: asyncio.Queue[Tuple[str, Payment]] = asyncio.Queue(0) async def payment_received() -> None: while True: - payment: Payment = await payment_queue.get() - if payment.wallet_id == this_wallet_id: - logger.debug("payment received", payment) - await send_queue.put(("payment-received", payment)) + try: + async with async_timeout.timeout(1): + payment: Payment = await payment_queue.get() + if payment.wallet_id == this_wallet_id: + logger.debug("sse listener: payment receieved", payment) + await send_queue.put(("payment-received", payment)) + except asyncio.TimeoutError: + pass - asyncio.create_task(payment_received()) + task = asyncio.create_task(payment_received()) try: while True: + if await request.is_disconnected(): + await request.close() + break typ, data = await send_queue.get() - if data: jdata = json.dumps(dict(data.dict(), pending=False)) - # yield dict(id=1, event="this", data="1234") - # await asyncio.sleep(2) yield dict(data=jdata, event=typ) - # yield dict(data=jdata.encode("utf-8"), event=typ.encode("utf-8")) - except asyncio.CancelledError: + except asyncio.CancelledError as e: + logger.debug(f"CancelledError on listener {uid}: {e}") + api_invoice_listeners.pop(uid) + task.cancel() return @@ -405,7 +418,9 @@ async def api_payments_sse( request: Request, wallet: WalletTypeInfo = Depends(get_key_type) ): return EventSourceResponse( - subscribe(request, wallet.wallet), ping=20, media_type="text/event-stream" + subscribe_wallet_invoices(request, wallet.wallet), + ping=20, + media_type="text/event-stream", ) diff --git a/lnbits/core/views/public_api.py b/lnbits/core/views/public_api.py index 2d2cdd66..9b0ebc98 100644 --- a/lnbits/core/views/public_api.py +++ b/lnbits/core/views/public_api.py @@ -46,8 +46,8 @@ async def api_public_payment_longpolling(payment_hash): payment_queue = asyncio.Queue(0) - logger.debug("adding standalone invoice listener", payment_hash, payment_queue) - api_invoice_listeners.append(payment_queue) + logger.debug(f"adding standalone invoice listener for hash: {payment_hash}") + api_invoice_listeners[payment_hash] = payment_queue response = None diff --git a/lnbits/extensions/boltcards/tasks.py b/lnbits/extensions/boltcards/tasks.py index 1b51c98b..c1e99b76 100644 --- a/lnbits/extensions/boltcards/tasks.py +++ b/lnbits/extensions/boltcards/tasks.py @@ -5,6 +5,7 @@ import httpx from lnbits.core import db as core_db from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import create_refund, get_hit @@ -12,7 +13,7 @@ from .crud import create_refund, get_hit async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/boltz/boltz.py b/lnbits/extensions/boltz/boltz.py index 4e5fecd0..ac99d4f4 100644 --- a/lnbits/extensions/boltz/boltz.py +++ b/lnbits/extensions/boltz/boltz.py @@ -34,8 +34,8 @@ from .models import ( from .utils import check_balance, get_timestamp, req_wrap net = NETWORKS[BOLTZ_NETWORK] -logger.debug(f"BOLTZ_URL: {BOLTZ_URL}") -logger.debug(f"Bitcoin Network: {net['name']}") +logger.trace(f"BOLTZ_URL: {BOLTZ_URL}") +logger.trace(f"Bitcoin Network: {net['name']}") async def create_swap(data: CreateSubmarineSwap) -> SubmarineSwap: diff --git a/lnbits/extensions/boltz/mempool.py b/lnbits/extensions/boltz/mempool.py index ee305257..a44c0f02 100644 --- a/lnbits/extensions/boltz/mempool.py +++ b/lnbits/extensions/boltz/mempool.py @@ -11,8 +11,8 @@ from lnbits.settings import BOLTZ_MEMPOOL_SPACE_URL, BOLTZ_MEMPOOL_SPACE_URL_WS from .utils import req_wrap -logger.debug(f"BOLTZ_MEMPOOL_SPACE_URL: {BOLTZ_MEMPOOL_SPACE_URL}") -logger.debug(f"BOLTZ_MEMPOOL_SPACE_URL_WS: {BOLTZ_MEMPOOL_SPACE_URL_WS}") +logger.trace(f"BOLTZ_MEMPOOL_SPACE_URL: {BOLTZ_MEMPOOL_SPACE_URL}") +logger.trace(f"BOLTZ_MEMPOOL_SPACE_URL_WS: {BOLTZ_MEMPOOL_SPACE_URL_WS}") websocket_url = f"{BOLTZ_MEMPOOL_SPACE_URL_WS}/api/v1/ws" diff --git a/lnbits/extensions/boltz/tasks.py b/lnbits/extensions/boltz/tasks.py index d6f72edf..ace94557 100644 --- a/lnbits/extensions/boltz/tasks.py +++ b/lnbits/extensions/boltz/tasks.py @@ -5,6 +5,7 @@ from loguru import logger from lnbits.core.models import Payment from lnbits.core.services import check_transaction_status +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .boltz import ( @@ -127,7 +128,7 @@ async def check_for_pending_swaps(): async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/copilot/tasks.py b/lnbits/extensions/copilot/tasks.py index f3c5cff8..c59ef4cc 100644 --- a/lnbits/extensions/copilot/tasks.py +++ b/lnbits/extensions/copilot/tasks.py @@ -7,6 +7,7 @@ from starlette.exceptions import HTTPException from lnbits.core import db as core_db from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_copilot @@ -15,7 +16,7 @@ from .views import updater async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/jukebox/tasks.py b/lnbits/extensions/jukebox/tasks.py index 70a2e65d..5614d926 100644 --- a/lnbits/extensions/jukebox/tasks.py +++ b/lnbits/extensions/jukebox/tasks.py @@ -1,6 +1,7 @@ import asyncio from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import update_jukebox_payment @@ -8,7 +9,7 @@ from .crud import update_jukebox_payment async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/livestream/tasks.py b/lnbits/extensions/livestream/tasks.py index 85bdd5e0..626c698c 100644 --- a/lnbits/extensions/livestream/tasks.py +++ b/lnbits/extensions/livestream/tasks.py @@ -6,7 +6,7 @@ from loguru import logger from lnbits.core import db as core_db from lnbits.core.crud import create_payment from lnbits.core.models import Payment -from lnbits.helpers import urlsafe_short_hash +from lnbits.helpers import get_current_extension_name, urlsafe_short_hash from lnbits.tasks import internal_invoice_listener, register_invoice_listener from .crud import get_livestream_by_track, get_producer, get_track @@ -14,7 +14,7 @@ from .crud import get_livestream_by_track, get_producer, get_track async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/lnaddress/tasks.py b/lnbits/extensions/lnaddress/tasks.py index 9abe10c3..0c377eec 100644 --- a/lnbits/extensions/lnaddress/tasks.py +++ b/lnbits/extensions/lnaddress/tasks.py @@ -3,6 +3,7 @@ import asyncio import httpx from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_address, get_domain, set_address_paid, set_address_renewed @@ -10,7 +11,7 @@ from .crud import get_address, get_domain, set_address_paid, set_address_renewed async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/lnticket/__init__.py b/lnbits/extensions/lnticket/__init__.py index 792b1175..cb793f4d 100644 --- a/lnbits/extensions/lnticket/__init__.py +++ b/lnbits/extensions/lnticket/__init__.py @@ -1,4 +1,5 @@ import asyncio +import json from fastapi import APIRouter diff --git a/lnbits/extensions/lnticket/tasks.py b/lnbits/extensions/lnticket/tasks.py index 7e672115..746ebea9 100644 --- a/lnbits/extensions/lnticket/tasks.py +++ b/lnbits/extensions/lnticket/tasks.py @@ -3,6 +3,7 @@ import asyncio from loguru import logger from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_ticket, set_ticket_paid @@ -10,7 +11,7 @@ from .crud import get_ticket, set_ticket_paid async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index 525d36ce..86f1579a 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -5,6 +5,7 @@ import httpx from lnbits.core import db as core_db from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_pay_link @@ -12,7 +13,7 @@ from .crud import get_pay_link async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/lnurlpayout/tasks.py b/lnbits/extensions/lnurlpayout/tasks.py index b621876c..71f299be 100644 --- a/lnbits/extensions/lnurlpayout/tasks.py +++ b/lnbits/extensions/lnurlpayout/tasks.py @@ -10,6 +10,7 @@ from lnbits.core.crud import get_wallet from lnbits.core.models import Payment from lnbits.core.services import pay_invoice from lnbits.core.views.api import api_payments_decode +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_lnurlpayout_from_wallet @@ -17,7 +18,7 @@ from .crud import get_lnurlpayout_from_wallet async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/satspay/tasks.py b/lnbits/extensions/satspay/tasks.py index d325405b..46c16bbc 100644 --- a/lnbits/extensions/satspay/tasks.py +++ b/lnbits/extensions/satspay/tasks.py @@ -4,6 +4,7 @@ from loguru import logger from lnbits.core.models import Payment from lnbits.extensions.satspay.crud import check_address_balance, get_charge +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener # from .crud import get_ticket, set_ticket_paid @@ -11,7 +12,7 @@ from lnbits.tasks import register_invoice_listener async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/scrub/tasks.py b/lnbits/extensions/scrub/tasks.py index 87e1364b..320d34da 100644 --- a/lnbits/extensions/scrub/tasks.py +++ b/lnbits/extensions/scrub/tasks.py @@ -9,6 +9,7 @@ from fastapi import HTTPException from lnbits import bolt11 from lnbits.core.models import Payment from lnbits.core.services import pay_invoice +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .crud import get_scrub_by_wallet @@ -16,7 +17,7 @@ from .crud import get_scrub_by_wallet async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/splitpayments/tasks.py b/lnbits/extensions/splitpayments/tasks.py index 0948e849..b7cf1750 100644 --- a/lnbits/extensions/splitpayments/tasks.py +++ b/lnbits/extensions/splitpayments/tasks.py @@ -6,7 +6,7 @@ from loguru import logger from lnbits.core import db as core_db from lnbits.core.crud import create_payment from lnbits.core.models import Payment -from lnbits.helpers import urlsafe_short_hash +from lnbits.helpers import get_current_extension_name, urlsafe_short_hash from lnbits.tasks import internal_invoice_queue, register_invoice_listener from .crud import get_targets @@ -14,7 +14,7 @@ from .crud import get_targets async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/subdomains/tasks.py b/lnbits/extensions/subdomains/tasks.py index d8f35161..04ee2dd4 100644 --- a/lnbits/extensions/subdomains/tasks.py +++ b/lnbits/extensions/subdomains/tasks.py @@ -3,6 +3,7 @@ import asyncio import httpx from lnbits.core.models import Payment +from lnbits.helpers import get_current_extension_name from lnbits.tasks import register_invoice_listener from .cloudflare import cloudflare_create_subdomain @@ -11,7 +12,7 @@ from .crud import get_domain, set_subdomain_paid async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index af9663cc..f18d1689 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -4,7 +4,7 @@ import json from lnbits.core import db as core_db from lnbits.core.crud import create_payment from lnbits.core.models import Payment -from lnbits.helpers import urlsafe_short_hash +from lnbits.helpers import get_current_extension_name, urlsafe_short_hash from lnbits.tasks import internal_invoice_queue, register_invoice_listener from .crud import get_tpos @@ -12,7 +12,7 @@ from .crud import get_tpos async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue) + register_invoice_listener(invoice_queue, get_current_extension_name()) while True: payment = await invoice_queue.get() diff --git a/lnbits/helpers.py b/lnbits/helpers.py index e97fc7bb..e213240c 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -183,3 +183,26 @@ def template_renderer(additional_folders: List = []) -> Jinja2Templates: t.env.globals["VENDORED_CSS"] = ["/static/bundle.css"] return t + + +def get_current_extension_name() -> str: + """ + Returns the name of the extension that calls this method. + """ + import inspect + import json + import os + + callee_filepath = inspect.stack()[1].filename + callee_dirname, callee_filename = os.path.split(callee_filepath) + + path = os.path.normpath(callee_dirname) + extension_director_name = path.split(os.sep)[-1] + try: + config_path = os.path.join(callee_dirname, "config.json") + with open(config_path) as json_file: + config = json.load(json_file) + ext_name = config["name"] + except: + ext_name = extension_director_name + return ext_name diff --git a/lnbits/tasks.py b/lnbits/tasks.py index 41287ff2..94e43dcf 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -1,8 +1,9 @@ import asyncio import time import traceback +import uuid from http import HTTPStatus -from typing import Callable, List +from typing import Callable, Dict, List from fastapi.exceptions import HTTPException from loguru import logger @@ -18,20 +19,6 @@ from lnbits.settings import WALLET from .core import db -deferred_async: List[Callable] = [] - - -def record_async(func: Callable) -> Callable: - def recorder(state): - deferred_async.append(func) - - return recorder - - -async def run_deferred_async(): - for func in deferred_async: - asyncio.create_task(catch_everything_and_restart(func)) - async def catch_everything_and_restart(func): try: @@ -50,18 +37,48 @@ async def send_push_promise(a, b) -> None: pass -invoice_listeners: List[asyncio.Queue] = [] +class SseListenersDict(dict): + """ + A dict of sse listeners. + """ + + def __init__(self, name: str = None): + self.name = name or f"sse_listener_{str(uuid.uuid4())[:8]}" + + def __setitem__(self, key, value): + assert type(key) == str, f"{key} is not a string" + assert type(value) == asyncio.Queue, f"{value} is not an asyncio.Queue" + logger.trace(f"sse: adding listener {key} to {self.name}. len = {len(self)+1}") + return super().__setitem__(key, value) + + def __delitem__(self, key): + logger.trace(f"sse: removing listener from {self.name}. len = {len(self)-1}") + return super().__delitem__(key) + + _RaiseKeyError = object() # singleton for no-default behavior + + def pop(self, key, v=_RaiseKeyError) -> None: + logger.trace(f"sse: removing listener from {self.name}. len = {len(self)-1}") + return super().pop(key) -def register_invoice_listener(send_chan: asyncio.Queue): +invoice_listeners: Dict[str, asyncio.Queue] = SseListenersDict("invoice_listeners") + + +def register_invoice_listener(send_chan: asyncio.Queue, name: str = None): """ - A method intended for extensions to call when they want to be notified about - new invoice payments incoming. + A method intended for extensions (and core/tasks.py) to call when they want to be notified about + new invoice payments incoming. Will emit all incoming payments. """ - invoice_listeners.append(send_chan) + name_unique = f"{name or 'no_name'}_{str(uuid.uuid4())[:8]}" + logger.trace(f"sse: registering invoice listener {name_unique}") + invoice_listeners[name_unique] = send_chan async def webhook_handler(): + """ + Returns the webhook_handler for the selected wallet if present. Used by API. + """ handler = getattr(WALLET, "webhook_listener", None) if handler: return await handler() @@ -72,18 +89,36 @@ internal_invoice_queue: asyncio.Queue = asyncio.Queue(0) async def internal_invoice_listener(): + """ + internal_invoice_queue will be filled directly in core/services.py + after the payment was deemed to be settled internally. + + Called by the app startup sequence. + """ while True: checking_id = await internal_invoice_queue.get() + logger.info("> got internal payment notification", checking_id) asyncio.create_task(invoice_callback_dispatcher(checking_id)) async def invoice_listener(): + """ + invoice_listener will collect all invoices that come directly + from the backend wallet. + + Called by the app startup sequence. + """ async for checking_id in WALLET.paid_invoices_stream(): logger.info("> got a payment notification", checking_id) asyncio.create_task(invoice_callback_dispatcher(checking_id)) async def check_pending_payments(): + """ + check_pending_payments is called during startup to check for pending payments with + the backend and also to delete expired invoices. Incoming payments will be + checked only once, outgoing pending payments will be checked regularly. + """ outgoing = True incoming = True @@ -133,9 +168,14 @@ async def perform_balance_checks(): async def invoice_callback_dispatcher(checking_id: str): + """ + Takes incoming payments, sets pending=False, and dispatches them to + invoice_listeners from core and extensions. + """ payment = await get_standalone_payment(checking_id, incoming=True) if payment and payment.is_in: - logger.trace("sending invoice callback for payment", checking_id) + logger.trace(f"sse sending invoice callback for payment {checking_id}") await payment.set_pending(False) - for send_chan in invoice_listeners: + for chan_name, send_chan in invoice_listeners.items(): + logger.trace(f"sse sending to chan: {chan_name}") await send_chan.put(payment) diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index 8424001b..a07ef4d8 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -8,9 +8,7 @@ from typing import AsyncGenerator, Dict, Optional from environs import Env # type: ignore from loguru import logger -from lnbits.helpers import urlsafe_short_hash - -from ..bolt11 import decode, encode +from ..bolt11 import Invoice, decode, encode from .base import ( InvoiceResponse, PaymentResponse, @@ -24,6 +22,16 @@ env.read_env() class FakeWallet(Wallet): + queue: asyncio.Queue = asyncio.Queue(0) + secret: str = env.str("FAKE_WALLET_SECTRET", default="ToTheMoon1") + privkey: str = hashlib.pbkdf2_hmac( + "sha256", + secret.encode("utf-8"), + ("FakeWallet").encode("utf-8"), + 2048, + 32, + ).hex() + async def status(self) -> StatusResponse: logger.info( "FakeWallet funding source is for using LNbits as a centralised, stand-alone payment system with brrrrrr." @@ -39,18 +47,12 @@ class FakeWallet(Wallet): ) -> InvoiceResponse: # we set a default secret since FakeWallet is used for internal=True invoices # and the user might not have configured a secret yet - secret = env.str("FAKE_WALLET_SECTRET", default="ToTheMoon1") + data: Dict = { "out": False, "amount": amount, "currency": "bc", - "privkey": hashlib.pbkdf2_hmac( - "sha256", - secret.encode("utf-8"), - ("FakeWallet").encode("utf-8"), - 2048, - 32, - ).hex(), + "privkey": self.privkey, "memo": None, "description_hash": None, "description": "", @@ -86,8 +88,9 @@ class FakeWallet(Wallet): invoice = decode(bolt11) if ( hasattr(invoice, "checking_id") - and invoice.checking_id[6:] == data["privkey"][:6] # type: ignore + and invoice.checking_id[:6] == self.privkey[:6] # type: ignore ): + await self.queue.put(invoice) return PaymentResponse(True, invoice.payment_hash, 0) else: return PaymentResponse( @@ -101,7 +104,6 @@ class FakeWallet(Wallet): return PaymentStatus(None) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - self.queue: asyncio.Queue = asyncio.Queue(0) while True: - value = await self.queue.get() - yield value + value: Invoice = await self.queue.get() + yield value.payment_hash diff --git a/poetry.lock b/poetry.lock index 2a57a5c1..343fffbf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,6 +46,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} + [[package]] name = "attrs" version = "21.2.0" @@ -111,7 +122,7 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] -name = "cerberus" +name = "Cerberus" version = "1.3.4" description = "Lightweight, extensible schema and data validation tool for Python dictionaries." category = "main" @@ -402,7 +413,7 @@ plugins = ["setuptools"] requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] -name = "jinja2" +name = "Jinja2" version = "3.0.1" description = "A very fast and expressive template engine." category = "main" @@ -444,7 +455,7 @@ win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} dev = ["Sphinx (>=2.2.1)", "black (>=19.10b0)", "codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)", "tox-travis (>=0.12)"] [[package]] -name = "markupsafe" +name = "MarkupSafe" version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" @@ -648,12 +659,12 @@ optional = false python-versions = ">=3.7,<4.0" [package.dependencies] -pyln-bolt7 = ">=1.0,<2.0" -pyln-proto = ">=0.11,<0.12" +pyln-bolt7 = ">=1.0" +pyln-proto = ">=0.12" [[package]] name = "pyln-proto" -version = "0.11.1" +version = "0.12.0" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." category = "main" optional = false @@ -686,7 +697,7 @@ optional = false python-versions = "*" [[package]] -name = "pyqrcode" +name = "PyQRCode" version = "1.2.1" description = "A QR code generator written purely in Python with SVG, EPS, PNG and terminal output." category = "main" @@ -697,7 +708,7 @@ python-versions = "*" PNG = ["pypng (>=0.0.13)"] [[package]] -name = "pyscss" +name = "pyScss" version = "1.4.0" description = "pyScss, a Scss compiler for Python" category = "main" @@ -780,7 +791,7 @@ python-versions = ">=3.5" cli = ["click (>=5.0)"] [[package]] -name = "pyyaml" +name = "PyYAML" version = "5.4.1" description = "YAML parser and emitter for Python" category = "main" @@ -788,7 +799,7 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] -name = "represent" +name = "Represent" version = "1.6.0.post0" description = "Create __repr__ automatically or declaratively." category = "main" @@ -864,7 +875,7 @@ optional = false python-versions = ">=3.5" [[package]] -name = "sqlalchemy" +name = "SQLAlchemy" version = "1.3.23" description = "Database Abstraction Library" category = "main" @@ -1059,6 +1070,10 @@ asn1crypto = [ {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, ] +async-timeout = [ + {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, + {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, +] attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, @@ -1101,7 +1116,7 @@ black = [ {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, ] -cerberus = [ +Cerberus = [ {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"}, ] certifi = [ @@ -1413,7 +1428,7 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -jinja2 = [ +Jinja2 = [ {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, ] @@ -1425,7 +1440,7 @@ loguru = [ {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, ] -markupsafe = [ +MarkupSafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, @@ -1681,8 +1696,8 @@ pyln-client = [ {file = "pyln_client-0.11.1-py3-none-any.whl", hash = "sha256:497db443406b80c98c0434e2938eb1b2a17e88fd9aa63b018124068198df6141"}, ] pyln-proto = [ - {file = "pyln-proto-0.11.1.tar.gz", hash = "sha256:9bed240f41917c4fd526b767218a77d0fbe69242876eef72c35a856796f922d6"}, - {file = "pyln_proto-0.11.1-py3-none-any.whl", hash = "sha256:27b2e04a81b894f69018279c0ce4aa2e7ccd03b86dd9783f96b9d8d1498c8393"}, + {file = "pyln-proto-0.12.0.tar.gz", hash = "sha256:3214d99d8385f2135a94937f0dc1da626a33b257e9ebc320841656edaefabbe5"}, + {file = "pyln_proto-0.12.0-py3-none-any.whl", hash = "sha256:dedef5d8e476a9ade5a0b2eb919ccc37e4a57f2a78fdc399f1c5e0de17e41604"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1691,11 +1706,11 @@ pyparsing = [ pypng = [ {file = "pypng-0.0.21-py3-none-any.whl", hash = "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd"}, ] -pyqrcode = [ +PyQRCode = [ {file = "PyQRCode-1.2.1.tar.gz", hash = "sha256:fdbf7634733e56b72e27f9bce46e4550b75a3a2c420414035cae9d9d26b234d5"}, {file = "PyQRCode-1.2.1.zip", hash = "sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6"}, ] -pyscss = [ +pyScss = [ {file = "pyScss-1.4.0.tar.gz", hash = "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff"}, ] PySocks = [ @@ -1719,7 +1734,7 @@ python-dotenv = [ {file = "python-dotenv-0.19.0.tar.gz", hash = "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"}, {file = "python_dotenv-0.19.0-py2.py3-none-any.whl", hash = "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1"}, ] -pyyaml = [ +PyYAML = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, @@ -1750,7 +1765,7 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] -represent = [ +Represent = [ {file = "Represent-1.6.0.post0-py2.py3-none-any.whl", hash = "sha256:99142650756ef1998ce0661568f54a47dac8c638fb27e3816c02536575dbba8c"}, {file = "Represent-1.6.0.post0.tar.gz", hash = "sha256:026c0de2ee8385d1255b9c2426cd4f03fe9177ac94c09979bc601946c8493aa0"}, ] @@ -1799,7 +1814,7 @@ sniffio = [ {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, ] -sqlalchemy = [ +SQLAlchemy = [ {file = "SQLAlchemy-1.3.23-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:fd3b96f8c705af8e938eaa99cbd8fd1450f632d38cad55e7367c33b263bf98ec"}, {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:29cccc9606750fe10c5d0e8bd847f17a97f3850b8682aef1f56f5d5e1a5a64b1"}, {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:927ce09e49bff3104459e1451ce82983b0a3062437a07d883a4c66f0b344c9b5"}, diff --git a/pyproject.toml b/pyproject.toml index 864500f7..19dac860 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,6 @@ asgiref = "3.4.1" attrs = "21.2.0" bech32 = "1.2.0" bitstring = "3.1.9" -cerberus = "1.3.4" certifi = "2021.5.30" charset-normalizer = "2.0.6" click = "8.0.1" @@ -62,6 +61,8 @@ cffi = "1.15.0" websocket-client = "1.3.3" grpcio = "^1.49.1" protobuf = "^4.21.6" +Cerberus = "^1.3.4" +async-timeout = "^4.0.2" pyln-client = "0.11.1" [tool.poetry.dev-dependencies] diff --git a/requirements.txt b/requirements.txt index 697ea1d4..eb9a6e5e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -51,3 +51,5 @@ uvloop==0.16.0 watchfiles==0.16.0 websockets==10.3 websocket-client==1.3.3 +async-timeout==4.0.2 +setuptools==65.4.0 \ No newline at end of file From bc2068cc87f5d7b867ce0e9f4ccc8fabf8af7732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 6 Oct 2022 09:42:38 +0200 Subject: [PATCH 20/20] fix poetry lock in main --- poetry.lock | 152 ++++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/poetry.lock b/poetry.lock index 343fffbf..5b283d75 100644 --- a/poetry.lock +++ b/poetry.lock @@ -196,7 +196,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.4.4" +version = "6.5.0" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -589,7 +589,7 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.21.6" +version = "4.21.7" description = "" category = "main" optional = false @@ -659,12 +659,12 @@ optional = false python-versions = ">=3.7,<4.0" [package.dependencies] -pyln-bolt7 = ">=1.0" -pyln-proto = ">=0.12" +pyln-bolt7 = ">=1.0,<2.0" +pyln-proto = ">=0.11,<0.12" [[package]] name = "pyln-proto" -version = "0.12.0" +version = "0.11.1" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." category = "main" optional = false @@ -839,14 +839,14 @@ cffi = ">=1.3.0" [[package]] name = "setuptools" -version = "65.4.0" +version = "65.4.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -1051,7 +1051,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black ( [metadata] lock-version = "1.1" python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7" -content-hash = "72e4462285d0bc5e2cb83c88c613726beced959b268bd30b984d8baaeff178ea" +content-hash = "c4a01d5bfc24a8008348b6bd954717354554310afaaecbfc2a14222ad25aca42" [metadata.files] aiofiles = [ @@ -1224,56 +1224,56 @@ colorama = [ {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] coverage = [ - {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, - {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, - {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, - {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, - {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, - {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, - {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, - {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, - {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, - {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, - {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, - {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, - {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, - {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, - {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, - {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, ] cryptography = [ {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"}, @@ -1573,20 +1573,20 @@ pluggy = [ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] protobuf = [ - {file = "protobuf-4.21.6-cp310-abi3-win32.whl", hash = "sha256:49f88d56a9180dbb7f6199c920f5bb5c1dd0172f672983bb281298d57c2ac8eb"}, - {file = "protobuf-4.21.6-cp310-abi3-win_amd64.whl", hash = "sha256:7a6cc8842257265bdfd6b74d088b829e44bcac3cca234c5fdd6052730017b9ea"}, - {file = "protobuf-4.21.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ba596b9ffb85c909fcfe1b1a23136224ed678af3faf9912d3fa483d5f9813c4e"}, - {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4143513c766db85b9d7c18dbf8339673c8a290131b2a0fe73855ab20770f72b0"}, - {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b6cea204865595a92a7b240e4b65bcaaca3ad5d2ce25d9db3756eba06041138e"}, - {file = "protobuf-4.21.6-cp37-cp37m-win32.whl", hash = "sha256:9666da97129138585b26afcb63ad4887f602e169cafe754a8258541c553b8b5d"}, - {file = "protobuf-4.21.6-cp37-cp37m-win_amd64.whl", hash = "sha256:308173d3e5a3528787bb8c93abea81d5a950bdce62840d9760effc84127fb39c"}, - {file = "protobuf-4.21.6-cp38-cp38-win32.whl", hash = "sha256:aa29113ec901281f29d9d27b01193407a98aa9658b8a777b0325e6d97149f5ce"}, - {file = "protobuf-4.21.6-cp38-cp38-win_amd64.whl", hash = "sha256:8f9e60f7d44592c66e7b332b6a7b4b6e8d8b889393c79dbc3a91f815118f8eac"}, - {file = "protobuf-4.21.6-cp39-cp39-win32.whl", hash = "sha256:80e6540381080715fddac12690ee42d087d0d17395f8d0078dfd6f1181e7be4c"}, - {file = "protobuf-4.21.6-cp39-cp39-win_amd64.whl", hash = "sha256:77b355c8604fe285536155286b28b0c4cbc57cf81b08d8357bf34829ea982860"}, - {file = "protobuf-4.21.6-py2.py3-none-any.whl", hash = "sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9"}, - {file = "protobuf-4.21.6-py3-none-any.whl", hash = "sha256:c7c864148a237f058c739ae7a05a2b403c0dfa4ce7d1f3e5213f352ad52d57c6"}, - {file = "protobuf-4.21.6.tar.gz", hash = "sha256:6b1040a5661cd5f6e610cbca9cfaa2a17d60e2bb545309bc1b278bb05be44bdd"}, + {file = "protobuf-4.21.7-cp310-abi3-win32.whl", hash = "sha256:c7cb105d69a87416bd9023e64324e1c089593e6dae64d2536f06bcbe49cd97d8"}, + {file = "protobuf-4.21.7-cp310-abi3-win_amd64.whl", hash = "sha256:3ec85328a35a16463c6f419dbce3c0fc42b3e904d966f17f48bae39597c7a543"}, + {file = "protobuf-4.21.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:db9056b6a11cb5131036d734bcbf91ef3ef9235d6b681b2fc431cbfe5a7f2e56"}, + {file = "protobuf-4.21.7-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:ca200645d6235ce0df3ccfdff1567acbab35c4db222a97357806e015f85b5744"}, + {file = "protobuf-4.21.7-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b019c79e23a80735cc8a71b95f76a49a262f579d6b84fd20a0b82279f40e2cc1"}, + {file = "protobuf-4.21.7-cp37-cp37m-win32.whl", hash = "sha256:d3f89ccf7182293feba2de2739c8bf34fed1ed7c65a5cf987be00311acac57c1"}, + {file = "protobuf-4.21.7-cp37-cp37m-win_amd64.whl", hash = "sha256:a74d96cd960b87b4b712797c741bb3ea3a913f5c2dc4b6cbe9c0f8360b75297d"}, + {file = "protobuf-4.21.7-cp38-cp38-win32.whl", hash = "sha256:8e09d1916386eca1ef1353767b6efcebc0a6859ed7f73cb7fb974feba3184830"}, + {file = "protobuf-4.21.7-cp38-cp38-win_amd64.whl", hash = "sha256:9e355f2a839d9930d83971b9f562395e13493f0e9211520f8913bd11efa53c02"}, + {file = "protobuf-4.21.7-cp39-cp39-win32.whl", hash = "sha256:f370c0a71712f8965023dd5b13277444d3cdfecc96b2c778b0e19acbfd60df6e"}, + {file = "protobuf-4.21.7-cp39-cp39-win_amd64.whl", hash = "sha256:9643684232b6b340b5e63bb69c9b4904cdd39e4303d498d1a92abddc7e895b7f"}, + {file = "protobuf-4.21.7-py2.py3-none-any.whl", hash = "sha256:8066322588d4b499869bf9f665ebe448e793036b552f68c585a9b28f1e393f66"}, + {file = "protobuf-4.21.7-py3-none-any.whl", hash = "sha256:58b81358ec6c0b5d50df761460ae2db58405c063fd415e1101209221a0a810e1"}, + {file = "protobuf-4.21.7.tar.gz", hash = "sha256:71d9dba03ed3432c878a801e2ea51e034b0ea01cf3a4344fb60166cb5f6c8757"}, ] psycopg2-binary = [ {file = "psycopg2-binary-2.9.1.tar.gz", hash = "sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773"}, @@ -1696,8 +1696,8 @@ pyln-client = [ {file = "pyln_client-0.11.1-py3-none-any.whl", hash = "sha256:497db443406b80c98c0434e2938eb1b2a17e88fd9aa63b018124068198df6141"}, ] pyln-proto = [ - {file = "pyln-proto-0.12.0.tar.gz", hash = "sha256:3214d99d8385f2135a94937f0dc1da626a33b257e9ebc320841656edaefabbe5"}, - {file = "pyln_proto-0.12.0-py3-none-any.whl", hash = "sha256:dedef5d8e476a9ade5a0b2eb919ccc37e4a57f2a78fdc399f1c5e0de17e41604"}, + {file = "pyln-proto-0.11.1.tar.gz", hash = "sha256:9bed240f41917c4fd526b767218a77d0fbe69242876eef72c35a856796f922d6"}, + {file = "pyln_proto-0.11.1-py3-none-any.whl", hash = "sha256:27b2e04a81b894f69018279c0ce4aa2e7ccd03b86dd9783f96b9d8d1498c8393"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1799,8 +1799,8 @@ secp256k1 = [ {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, ] setuptools = [ - {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, - {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, + {file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"}, + {file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"}, ] shortuuid = [ {file = "shortuuid-1.0.1-py3-none-any.whl", hash = "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77"},