From 35c5542b2f09dc4dbce6ba8dd3e1889b275a39d9 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 30 Nov 2022 16:24:13 +0100 Subject: [PATCH 1/3] restore 7f64f426c226977530bc983650efd5dbcd4afa84 --- .env.example | 5 + .github/codecov.yml | 9 + lnbits/commands.py | 16 +- lnbits/extensions/cashu/README.md | 11 + lnbits/extensions/cashu/__init__.py | 48 + lnbits/extensions/cashu/config.json | 7 + lnbits/extensions/cashu/crud.py | 63 + lnbits/extensions/cashu/migrations.py | 33 + lnbits/extensions/cashu/models.py | 147 ++ lnbits/extensions/cashu/static/js/base64.js | 37 + lnbits/extensions/cashu/static/js/dhke.js | 39 + .../cashu/static/js/noble-secp256k1.js | 1178 +++++++++ lnbits/extensions/cashu/static/js/utils.js | 23 + lnbits/extensions/cashu/tasks.py | 33 + .../cashu/templates/cashu/_api_docs.html | 80 + .../cashu/templates/cashu/_cashu.html | 13 + .../cashu/templates/cashu/index.html | 367 +++ .../cashu/templates/cashu/mint.html | 76 + .../cashu/templates/cashu/wallet.html | 2337 +++++++++++++++++ lnbits/extensions/cashu/views.py | 224 ++ lnbits/extensions/cashu/views_api.py | 382 +++ lnbits/helpers.py | 4 + poetry.lock | 744 +++--- pyproject.toml | 42 +- requirements.txt | 58 +- tests/data/mock_data.zip | Bin 30790 -> 37478 bytes tools/conv.py | 6 +- 27 files changed, 5624 insertions(+), 358 deletions(-) create mode 100644 .github/codecov.yml create mode 100644 lnbits/extensions/cashu/README.md create mode 100644 lnbits/extensions/cashu/__init__.py create mode 100644 lnbits/extensions/cashu/config.json create mode 100644 lnbits/extensions/cashu/crud.py create mode 100644 lnbits/extensions/cashu/migrations.py create mode 100644 lnbits/extensions/cashu/models.py create mode 100644 lnbits/extensions/cashu/static/js/base64.js create mode 100644 lnbits/extensions/cashu/static/js/dhke.js create mode 100644 lnbits/extensions/cashu/static/js/noble-secp256k1.js create mode 100644 lnbits/extensions/cashu/static/js/utils.js create mode 100644 lnbits/extensions/cashu/tasks.py create mode 100644 lnbits/extensions/cashu/templates/cashu/_api_docs.html create mode 100644 lnbits/extensions/cashu/templates/cashu/_cashu.html create mode 100644 lnbits/extensions/cashu/templates/cashu/index.html create mode 100644 lnbits/extensions/cashu/templates/cashu/mint.html create mode 100644 lnbits/extensions/cashu/templates/cashu/wallet.html create mode 100644 lnbits/extensions/cashu/views.py create mode 100644 lnbits/extensions/cashu/views_api.py diff --git a/.env.example b/.env.example index b7fb9f063..898f90bd6 100644 --- a/.env.example +++ b/.env.example @@ -103,3 +103,8 @@ ECLAIR_PASS=eclairpw # Enter /api in LightningTipBot to get your key LNTIPS_API_KEY=LNTIPS_ADMIN_KEY LNTIPS_API_ENDPOINT=https://ln.tips + +# Cashu Mint +# Use a long-enough random (!) private key. +# Once set, you cannot change this key as for now. +CASHU_PRIVATE_KEY="SuperSecretPrivateKey" diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000..e190e6aa8 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,9 @@ +coverage: + status: + patch: off + project: + default: + target: auto + # adjust accordingly based on how flaky your tests are + # this allows a 10% drop from the previous base commit coverage + threshold: 10% \ No newline at end of file diff --git a/lnbits/commands.py b/lnbits/commands.py index 0f7454f23..897390768 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -65,14 +65,14 @@ async def migrate_databases(): (db_name, version, version), ) - async def run_migration(db, migrations_module): - db_name = migrations_module.__name__.split(".")[-2] + async def run_migration(db, migrations_module, db_name): for key, migrate in migrations_module.__dict__.items(): match = match = matcher.match(key) if match: version = int(match.group(1)) if version > current_versions.get(db_name, 0): logger.debug(f"running migration {db_name}.{version}") + logger.debug(f"db = {db}") await migrate(db) if db.schema == None: @@ -97,20 +97,24 @@ async def migrate_databases(): rows = await (await conn.execute("SELECT * FROM dbversions")).fetchall() current_versions = {row["db"]: row["version"] for row in rows} matcher = re.compile(r"^m(\d\d\d)_") - await run_migration(conn, core_migrations) + db_name = core_migrations.__name__.split(".")[-2] + await run_migration(conn, core_migrations, db_name) for ext in get_valid_extensions(): try: - ext_migrations = importlib.import_module( - f"lnbits.extensions.{ext.code}.migrations" + + module_str = ( + ext.migration_module or f"lnbits.extensions.{ext.code}.migrations" ) + ext_migrations = importlib.import_module(module_str) ext_db = importlib.import_module(f"lnbits.extensions.{ext.code}").db + db_name = ext.db_name or module_str.split(".")[-2] except ImportError: raise ImportError( f"Please make sure that the extension `{ext.code}` has a migrations file." ) async with ext_db.connect() as ext_conn: - await run_migration(ext_conn, ext_migrations) + await run_migration(ext_conn, ext_migrations, db_name) logger.info("✔️ All migrations done.") diff --git a/lnbits/extensions/cashu/README.md b/lnbits/extensions/cashu/README.md new file mode 100644 index 000000000..8f53b474b --- /dev/null +++ b/lnbits/extensions/cashu/README.md @@ -0,0 +1,11 @@ +# Cashu + +## Create ecash mint for pegging in/out of ecash + + + +### Usage + +1. Enable extension +2. Create a Mint +3. Share wallet diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py new file mode 100644 index 000000000..e6507bba9 --- /dev/null +++ b/lnbits/extensions/cashu/__init__.py @@ -0,0 +1,48 @@ +import asyncio + +from environs import Env # type: ignore +from fastapi import APIRouter +from fastapi.staticfiles import StaticFiles + +from lnbits.db import Database +from lnbits.helpers import template_renderer +from lnbits.tasks import catch_everything_and_restart + +db = Database("ext_cashu") + +import sys + +cashu_static_files = [ + { + "path": "/cashu/static", + "app": StaticFiles(directory="lnbits/extensions/cashu/static"), + "name": "cashu_static", + } +] +from cashu.mint.ledger import Ledger + +env = Env() +env.read_env() + +ledger = Ledger( + db=db, + seed=env.str("CASHU_PRIVATE_KEY", default="SuperSecretPrivateKey"), + derivation_path="0/0/0/1", +) + +cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"]) + + +def cashu_renderer(): + return template_renderer(["lnbits/extensions/cashu/templates"]) + + +from .tasks import startup_cashu_mint, wait_for_paid_invoices +from .views import * # noqa +from .views_api import * # noqa + + +def cashu_start(): + loop = asyncio.get_event_loop() + loop.create_task(catch_everything_and_restart(startup_cashu_mint)) + loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/cashu/config.json b/lnbits/extensions/cashu/config.json new file mode 100644 index 000000000..af202d43c --- /dev/null +++ b/lnbits/extensions/cashu/config.json @@ -0,0 +1,7 @@ +{ + "name": "Cashu", + "short_description": "Ecash mint and wallet", + "icon": "account_balance", + "contributors": ["calle", "vlad", "arcbtc"], + "hidden": false +} diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py new file mode 100644 index 000000000..773a11fde --- /dev/null +++ b/lnbits/extensions/cashu/crud.py @@ -0,0 +1,63 @@ +import os +import random +import time +from binascii import hexlify, unhexlify +from typing import Any, List, Optional, Union + +from cashu.core.base import MintKeyset +from embit import bip32, bip39, ec, script +from embit.networks import NETWORKS +from loguru import logger + +from lnbits.db import Connection, Database +from lnbits.helpers import urlsafe_short_hash + +from . import db +from .models import Cashu, Pegs, Promises, Proof + + +async def create_cashu( + cashu_id: str, keyset_id: str, wallet_id: str, data: Cashu +) -> Cashu: + + await db.execute( + """ + INSERT INTO cashu.cashu (id, wallet, name, tickershort, fraction, maxsats, coins, keyset_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + cashu_id, + wallet_id, + data.name, + data.tickershort, + data.fraction, + data.maxsats, + data.coins, + keyset_id, + ), + ) + + cashu = await get_cashu(cashu_id) + assert cashu, "Newly created cashu couldn't be retrieved" + return cashu + + +async def get_cashu(cashu_id) -> Optional[Cashu]: + row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) + return Cashu(**row) if row else None + + +async def get_cashus(wallet_ids: Union[str, List[str]]) -> List[Cashu]: + if isinstance(wallet_ids, str): + wallet_ids = [wallet_ids] + + q = ",".join(["?"] * len(wallet_ids)) + rows = await db.fetchall( + f"SELECT * FROM cashu.cashu WHERE wallet IN ({q})", (*wallet_ids,) + ) + + return [Cashu(**row) for row in rows] + + +async def delete_cashu(cashu_id) -> None: + await db.execute("DELETE FROM cashu.cashu WHERE id = ?", (cashu_id,)) diff --git a/lnbits/extensions/cashu/migrations.py b/lnbits/extensions/cashu/migrations.py new file mode 100644 index 000000000..b54c41087 --- /dev/null +++ b/lnbits/extensions/cashu/migrations.py @@ -0,0 +1,33 @@ +async def m001_initial(db): + """ + Initial cashu table. + """ + await db.execute( + """ + CREATE TABLE cashu.cashu ( + id TEXT PRIMARY KEY, + wallet TEXT NOT NULL, + name TEXT NOT NULL, + tickershort TEXT DEFAULT 'sats', + fraction BOOL, + maxsats INT, + coins INT, + keyset_id TEXT NOT NULL, + issued_sat INT + ); + """ + ) + + """ + Initial cashus table. + """ + await db.execute( + """ + CREATE TABLE cashu.pegs ( + id TEXT PRIMARY KEY, + wallet TEXT NOT NULL, + inout BOOL NOT NULL, + amount INT + ); + """ + ) diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py new file mode 100644 index 000000000..c820d12ec --- /dev/null +++ b/lnbits/extensions/cashu/models.py @@ -0,0 +1,147 @@ +from sqlite3 import Row +from typing import List, Union + +from fastapi import Query +from pydantic import BaseModel + + +class Cashu(BaseModel): + id: str = Query(None) + name: str = Query(None) + wallet: str = Query(None) + tickershort: str = Query(None) + fraction: bool = Query(None) + maxsats: int = Query(0) + coins: int = Query(0) + keyset_id: str = Query(None) + + @classmethod + def from_row(cls, row: Row): + return cls(**dict(row)) + + +class Pegs(BaseModel): + id: str + wallet: str + inout: str + amount: str + + @classmethod + def from_row(cls, row: Row): + return cls(**dict(row)) + + +class PayLnurlWData(BaseModel): + lnurl: str + + +class Promises(BaseModel): + id: str + amount: int + B_b: str + C_b: str + cashu_id: str + + +class Proof(BaseModel): + amount: int + secret: str + C: str + reserved: bool = False # whether this proof is reserved for sending + send_id: str = "" # unique ID of send attempt + time_created: str = "" + time_reserved: str = "" + + @classmethod + def from_row(cls, row: Row): + return cls( + amount=row[0], + C=row[1], + secret=row[2], + reserved=row[3] or False, + send_id=row[4] or "", + time_created=row[5] or "", + time_reserved=row[6] or "", + ) + + @classmethod + def from_dict(cls, d: dict): + assert "secret" in d, "no secret in proof" + assert "amount" in d, "no amount in proof" + return cls( + amount=d.get("amount"), + C=d.get("C"), + secret=d.get("secret"), + reserved=d.get("reserved") or False, + send_id=d.get("send_id") or "", + time_created=d.get("time_created") or "", + time_reserved=d.get("time_reserved") or "", + ) + + def to_dict(self): + return dict(amount=self.amount, secret=self.secret, C=self.C) + + def __getitem__(self, key): + return self.__getattribute__(key) + + def __setitem__(self, key, val): + self.__setattr__(key, val) + + +class Proofs(BaseModel): + """TODO: Use this model""" + + proofs: List[Proof] + + +class Invoice(BaseModel): + amount: int + pr: str + hash: str + issued: bool = False + + @classmethod + def from_row(cls, row: Row): + return cls( + amount=int(row[0]), + pr=str(row[1]), + hash=str(row[2]), + issued=bool(row[3]), + ) + + +class BlindedMessage(BaseModel): + amount: int + B_: str + + +class BlindedSignature(BaseModel): + amount: int + C_: str + + @classmethod + def from_dict(cls, d: dict): + return cls( + amount=d["amount"], + C_=d["C_"], + ) + + +class MintPayloads(BaseModel): + blinded_messages: List[BlindedMessage] = [] + + +class SplitPayload(BaseModel): + proofs: List[Proof] + amount: int + output_data: MintPayloads + + +class CheckPayload(BaseModel): + proofs: List[Proof] + + +class MeltPayload(BaseModel): + proofs: List[Proof] + amount: int + invoice: str diff --git a/lnbits/extensions/cashu/static/js/base64.js b/lnbits/extensions/cashu/static/js/base64.js new file mode 100644 index 000000000..b150882f7 --- /dev/null +++ b/lnbits/extensions/cashu/static/js/base64.js @@ -0,0 +1,37 @@ +function unescapeBase64Url(str) { + return (str + '==='.slice((str.length + 3) % 4)) + .replace(/-/g, '+') + .replace(/_/g, '/') +} + +function escapeBase64Url(str) { + return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '') +} + +const uint8ToBase64 = (function (exports) { + 'use strict' + + var fromCharCode = String.fromCharCode + var encode = function encode(uint8array) { + var output = [] + + for (var i = 0, length = uint8array.length; i < length; i++) { + output.push(fromCharCode(uint8array[i])) + } + + return btoa(output.join('')) + } + + var asCharCode = function asCharCode(c) { + return c.charCodeAt(0) + } + + var decode = function decode(chars) { + return Uint8Array.from(atob(chars), asCharCode) + } + + exports.decode = decode + exports.encode = encode + + return exports +})({}) diff --git a/lnbits/extensions/cashu/static/js/dhke.js b/lnbits/extensions/cashu/static/js/dhke.js new file mode 100644 index 000000000..41c2fb46c --- /dev/null +++ b/lnbits/extensions/cashu/static/js/dhke.js @@ -0,0 +1,39 @@ +async function hashToCurve(secretMessage) { + console.log( + '### secretMessage', + nobleSecp256k1.utils.bytesToHex(secretMessage) + ) + let point + while (!point) { + const hash = await nobleSecp256k1.utils.sha256(secretMessage) + const hashHex = nobleSecp256k1.utils.bytesToHex(hash) + const pointX = '02' + hashHex + console.log('### pointX', pointX) + try { + point = nobleSecp256k1.Point.fromHex(pointX) + console.log('### point', point.toHex()) + } catch (error) { + secretMessage = await nobleSecp256k1.utils.sha256(secretMessage) + } + } + return point +} + +async function step1Alice(secretMessage) { + // todo: document & validate `secretMessage` format + secretMessage = uint8ToBase64.encode(secretMessage) + secretMessage = new TextEncoder().encode(secretMessage) + const Y = await hashToCurve(secretMessage) + const rpk = nobleSecp256k1.utils.randomPrivateKey() + const r = bytesToNumber(rpk) + const P = nobleSecp256k1.Point.fromPrivateKey(r) + const B_ = Y.add(P) + return {B_: B_.toHex(true), r: nobleSecp256k1.utils.bytesToHex(rpk)} +} + +function step3Alice(C_, r, A) { + // const rInt = BigInt(r) + const rInt = bytesToNumber(r) + const C = C_.subtract(A.multiply(rInt)) + return C +} diff --git a/lnbits/extensions/cashu/static/js/noble-secp256k1.js b/lnbits/extensions/cashu/static/js/noble-secp256k1.js new file mode 100644 index 000000000..6a6bd4417 --- /dev/null +++ b/lnbits/extensions/cashu/static/js/noble-secp256k1.js @@ -0,0 +1,1178 @@ +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? factory(exports) + : typeof define === 'function' && define.amd + ? define(['exports'], factory) + : ((global = + typeof globalThis !== 'undefined' ? globalThis : global || self), + factory((global.nobleSecp256k1 = {}))) +})(this, function (exports) { + 'use strict' + + const _nodeResolve_empty = {} + + const nodeCrypto = /*#__PURE__*/ Object.freeze({ + __proto__: null, + default: _nodeResolve_empty + }) + + /*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */ + const _0n = BigInt(0) + const _1n = BigInt(1) + const _2n = BigInt(2) + const _3n = BigInt(3) + const _8n = BigInt(8) + const POW_2_256 = _2n ** BigInt(256) + const CURVE = { + a: _0n, + b: BigInt(7), + P: POW_2_256 - _2n ** BigInt(32) - BigInt(977), + n: POW_2_256 - BigInt('432420386565659656852420866394968145599'), + h: _1n, + Gx: BigInt( + '55066263022277343669578718895168534326250603453777594175500187360389116729240' + ), + Gy: BigInt( + '32670510020758816978083085130507043184471273380659243275938904335757337482424' + ), + beta: BigInt( + '0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee' + ) + } + function weistrass(x) { + const {a, b} = CURVE + const x2 = mod(x * x) + const x3 = mod(x2 * x) + return mod(x3 + a * x + b) + } + const USE_ENDOMORPHISM = CURVE.a === _0n + class JacobianPoint { + constructor(x, y, z) { + this.x = x + this.y = y + this.z = z + } + static fromAffine(p) { + if (!(p instanceof Point)) { + throw new TypeError('JacobianPoint#fromAffine: expected Point') + } + return new JacobianPoint(p.x, p.y, _1n) + } + static toAffineBatch(points) { + const toInv = invertBatch(points.map(p => p.z)) + return points.map((p, i) => p.toAffine(toInv[i])) + } + static normalizeZ(points) { + return JacobianPoint.toAffineBatch(points).map(JacobianPoint.fromAffine) + } + equals(other) { + if (!(other instanceof JacobianPoint)) + throw new TypeError('JacobianPoint expected') + const {x: X1, y: Y1, z: Z1} = this + const {x: X2, y: Y2, z: Z2} = other + const Z1Z1 = mod(Z1 ** _2n) + const Z2Z2 = mod(Z2 ** _2n) + const U1 = mod(X1 * Z2Z2) + const U2 = mod(X2 * Z1Z1) + const S1 = mod(mod(Y1 * Z2) * Z2Z2) + const S2 = mod(mod(Y2 * Z1) * Z1Z1) + return U1 === U2 && S1 === S2 + } + negate() { + return new JacobianPoint(this.x, mod(-this.y), this.z) + } + double() { + const {x: X1, y: Y1, z: Z1} = this + const A = mod(X1 ** _2n) + const B = mod(Y1 ** _2n) + const C = mod(B ** _2n) + const D = mod(_2n * (mod((X1 + B) ** _2n) - A - C)) + const E = mod(_3n * A) + const F = mod(E ** _2n) + const X3 = mod(F - _2n * D) + const Y3 = mod(E * (D - X3) - _8n * C) + const Z3 = mod(_2n * Y1 * Z1) + return new JacobianPoint(X3, Y3, Z3) + } + add(other) { + if (!(other instanceof JacobianPoint)) + throw new TypeError('JacobianPoint expected') + const {x: X1, y: Y1, z: Z1} = this + const {x: X2, y: Y2, z: Z2} = other + if (X2 === _0n || Y2 === _0n) return this + if (X1 === _0n || Y1 === _0n) return other + const Z1Z1 = mod(Z1 ** _2n) + const Z2Z2 = mod(Z2 ** _2n) + const U1 = mod(X1 * Z2Z2) + const U2 = mod(X2 * Z1Z1) + const S1 = mod(mod(Y1 * Z2) * Z2Z2) + const S2 = mod(mod(Y2 * Z1) * Z1Z1) + const H = mod(U2 - U1) + const r = mod(S2 - S1) + if (H === _0n) { + if (r === _0n) { + return this.double() + } else { + return JacobianPoint.ZERO + } + } + const HH = mod(H ** _2n) + const HHH = mod(H * HH) + const V = mod(U1 * HH) + const X3 = mod(r ** _2n - HHH - _2n * V) + const Y3 = mod(r * (V - X3) - S1 * HHH) + const Z3 = mod(Z1 * Z2 * H) + return new JacobianPoint(X3, Y3, Z3) + } + subtract(other) { + return this.add(other.negate()) + } + multiplyUnsafe(scalar) { + const P0 = JacobianPoint.ZERO + if (typeof scalar === 'bigint' && scalar === _0n) return P0 + let n = normalizeScalar(scalar) + if (n === _1n) return this + if (!USE_ENDOMORPHISM) { + let p = P0 + let d = this + while (n > _0n) { + if (n & _1n) p = p.add(d) + d = d.double() + n >>= _1n + } + return p + } + let {k1neg, k1, k2neg, k2} = splitScalarEndo(n) + let k1p = P0 + let k2p = P0 + let d = this + while (k1 > _0n || k2 > _0n) { + if (k1 & _1n) k1p = k1p.add(d) + if (k2 & _1n) k2p = k2p.add(d) + d = d.double() + k1 >>= _1n + k2 >>= _1n + } + if (k1neg) k1p = k1p.negate() + if (k2neg) k2p = k2p.negate() + k2p = new JacobianPoint(mod(k2p.x * CURVE.beta), k2p.y, k2p.z) + return k1p.add(k2p) + } + precomputeWindow(W) { + const windows = USE_ENDOMORPHISM ? 128 / W + 1 : 256 / W + 1 + const points = [] + let p = this + let base = p + for (let window = 0; window < windows; window++) { + base = p + points.push(base) + for (let i = 1; i < 2 ** (W - 1); i++) { + base = base.add(p) + points.push(base) + } + p = base.double() + } + return points + } + wNAF(n, affinePoint) { + if (!affinePoint && this.equals(JacobianPoint.BASE)) + affinePoint = Point.BASE + const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1 + if (256 % W) { + throw new Error( + 'Point#wNAF: Invalid precomputation window, must be power of 2' + ) + } + let precomputes = affinePoint && pointPrecomputes.get(affinePoint) + if (!precomputes) { + precomputes = this.precomputeWindow(W) + if (affinePoint && W !== 1) { + precomputes = JacobianPoint.normalizeZ(precomputes) + pointPrecomputes.set(affinePoint, precomputes) + } + } + let p = JacobianPoint.ZERO + let f = JacobianPoint.ZERO + const windows = 1 + (USE_ENDOMORPHISM ? 128 / W : 256 / W) + const windowSize = 2 ** (W - 1) + const mask = BigInt(2 ** W - 1) + const maxNumber = 2 ** W + const shiftBy = BigInt(W) + for (let window = 0; window < windows; window++) { + const offset = window * windowSize + let wbits = Number(n & mask) + n >>= shiftBy + if (wbits > windowSize) { + wbits -= maxNumber + n += _1n + } + if (wbits === 0) { + let pr = precomputes[offset] + if (window % 2) pr = pr.negate() + f = f.add(pr) + } else { + let cached = precomputes[offset + Math.abs(wbits) - 1] + if (wbits < 0) cached = cached.negate() + p = p.add(cached) + } + } + return {p, f} + } + multiply(scalar, affinePoint) { + let n = normalizeScalar(scalar) + let point + let fake + if (USE_ENDOMORPHISM) { + const {k1neg, k1, k2neg, k2} = splitScalarEndo(n) + let {p: k1p, f: f1p} = this.wNAF(k1, affinePoint) + let {p: k2p, f: f2p} = this.wNAF(k2, affinePoint) + if (k1neg) k1p = k1p.negate() + if (k2neg) k2p = k2p.negate() + k2p = new JacobianPoint(mod(k2p.x * CURVE.beta), k2p.y, k2p.z) + point = k1p.add(k2p) + fake = f1p.add(f2p) + } else { + const {p, f} = this.wNAF(n, affinePoint) + point = p + fake = f + } + return JacobianPoint.normalizeZ([point, fake])[0] + } + toAffine(invZ = invert(this.z)) { + const {x, y, z} = this + const iz1 = invZ + const iz2 = mod(iz1 * iz1) + const iz3 = mod(iz2 * iz1) + const ax = mod(x * iz2) + const ay = mod(y * iz3) + const zz = mod(z * iz1) + if (zz !== _1n) throw new Error('invZ was invalid') + return new Point(ax, ay) + } + } + JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy, _1n) + JacobianPoint.ZERO = new JacobianPoint(_0n, _1n, _0n) + const pointPrecomputes = new WeakMap() + class Point { + constructor(x, y) { + this.x = x + this.y = y + } + _setWindowSize(windowSize) { + this._WINDOW_SIZE = windowSize + pointPrecomputes.delete(this) + } + static fromCompressedHex(bytes) { + const isShort = bytes.length === 32 + const x = bytesToNumber(isShort ? bytes : bytes.subarray(1)) + if (!isValidFieldElement(x)) throw new Error('Point is not on curve') + const y2 = weistrass(x) + let y = sqrtMod(y2) + const isYOdd = (y & _1n) === _1n + if (isShort) { + if (isYOdd) y = mod(-y) + } else { + const isFirstByteOdd = (bytes[0] & 1) === 1 + if (isFirstByteOdd !== isYOdd) y = mod(-y) + } + const point = new Point(x, y) + point.assertValidity() + return point + } + static fromUncompressedHex(bytes) { + const x = bytesToNumber(bytes.subarray(1, 33)) + const y = bytesToNumber(bytes.subarray(33, 65)) + const point = new Point(x, y) + point.assertValidity() + return point + } + static fromHex(hex) { + const bytes = ensureBytes(hex) + const len = bytes.length + const header = bytes[0] + if (len === 32 || (len === 33 && (header === 0x02 || header === 0x03))) { + return this.fromCompressedHex(bytes) + } + if (len === 65 && header === 0x04) return this.fromUncompressedHex(bytes) + throw new Error( + `Point.fromHex: received invalid point. Expected 32-33 compressed bytes or 65 uncompressed bytes, not ${len}` + ) + } + static fromPrivateKey(privateKey) { + return Point.BASE.multiply(normalizePrivateKey(privateKey)) + } + static fromSignature(msgHash, signature, recovery) { + msgHash = ensureBytes(msgHash) + const h = truncateHash(msgHash) + const {r, s} = normalizeSignature(signature) + if (recovery !== 0 && recovery !== 1) { + throw new Error('Cannot recover signature: invalid recovery bit') + } + const prefix = recovery & 1 ? '03' : '02' + const R = Point.fromHex(prefix + numTo32bStr(r)) + const {n} = CURVE + const rinv = invert(r, n) + const u1 = mod(-h * rinv, n) + const u2 = mod(s * rinv, n) + const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2) + if (!Q) throw new Error('Cannot recover signature: point at infinify') + Q.assertValidity() + return Q + } + toRawBytes(isCompressed = false) { + return hexToBytes(this.toHex(isCompressed)) + } + toHex(isCompressed = false) { + const x = numTo32bStr(this.x) + if (isCompressed) { + const prefix = this.y & _1n ? '03' : '02' + return `${prefix}${x}` + } else { + return `04${x}${numTo32bStr(this.y)}` + } + } + toHexX() { + return this.toHex(true).slice(2) + } + toRawX() { + return this.toRawBytes(true).slice(1) + } + assertValidity() { + const msg = 'Point is not on elliptic curve' + const {x, y} = this + if (!isValidFieldElement(x) || !isValidFieldElement(y)) + throw new Error(msg) + const left = mod(y * y) + const right = weistrass(x) + if (mod(left - right) !== _0n) throw new Error(msg) + } + equals(other) { + return this.x === other.x && this.y === other.y + } + negate() { + return new Point(this.x, mod(-this.y)) + } + double() { + return JacobianPoint.fromAffine(this).double().toAffine() + } + add(other) { + return JacobianPoint.fromAffine(this) + .add(JacobianPoint.fromAffine(other)) + .toAffine() + } + subtract(other) { + return this.add(other.negate()) + } + multiply(scalar) { + return JacobianPoint.fromAffine(this).multiply(scalar, this).toAffine() + } + multiplyAndAddUnsafe(Q, a, b) { + const P = JacobianPoint.fromAffine(this) + const aP = + a === _0n || a === _1n || this !== Point.BASE + ? P.multiplyUnsafe(a) + : P.multiply(a) + const bQ = JacobianPoint.fromAffine(Q).multiplyUnsafe(b) + const sum = aP.add(bQ) + return sum.equals(JacobianPoint.ZERO) ? undefined : sum.toAffine() + } + } + Point.BASE = new Point(CURVE.Gx, CURVE.Gy) + Point.ZERO = new Point(_0n, _0n) + function sliceDER(s) { + return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s + } + function parseDERInt(data) { + if (data.length < 2 || data[0] !== 0x02) { + throw new Error(`Invalid signature integer tag: ${bytesToHex(data)}`) + } + const len = data[1] + const res = data.subarray(2, len + 2) + if (!len || res.length !== len) { + throw new Error(`Invalid signature integer: wrong length`) + } + if (res[0] === 0x00 && res[1] <= 0x7f) { + throw new Error('Invalid signature integer: trailing length') + } + return {data: bytesToNumber(res), left: data.subarray(len + 2)} + } + function parseDERSignature(data) { + if (data.length < 2 || data[0] != 0x30) { + throw new Error(`Invalid signature tag: ${bytesToHex(data)}`) + } + if (data[1] !== data.length - 2) { + throw new Error('Invalid signature: incorrect length') + } + const {data: r, left: sBytes} = parseDERInt(data.subarray(2)) + const {data: s, left: rBytesLeft} = parseDERInt(sBytes) + if (rBytesLeft.length) { + throw new Error( + `Invalid signature: left bytes after parsing: ${bytesToHex(rBytesLeft)}` + ) + } + return {r, s} + } + class Signature { + constructor(r, s) { + this.r = r + this.s = s + this.assertValidity() + } + static fromCompact(hex) { + const arr = isUint8a(hex) + const name = 'Signature.fromCompact' + if (typeof hex !== 'string' && !arr) + throw new TypeError(`${name}: Expected string or Uint8Array`) + const str = arr ? bytesToHex(hex) : hex + if (str.length !== 128) throw new Error(`${name}: Expected 64-byte hex`) + return new Signature( + hexToNumber(str.slice(0, 64)), + hexToNumber(str.slice(64, 128)) + ) + } + static fromDER(hex) { + const arr = isUint8a(hex) + if (typeof hex !== 'string' && !arr) + throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`) + const {r, s} = parseDERSignature(arr ? hex : hexToBytes(hex)) + return new Signature(r, s) + } + static fromHex(hex) { + return this.fromDER(hex) + } + assertValidity() { + const {r, s} = this + if (!isWithinCurveOrder(r)) + throw new Error('Invalid Signature: r must be 0 < r < n') + if (!isWithinCurveOrder(s)) + throw new Error('Invalid Signature: s must be 0 < s < n') + } + hasHighS() { + const HALF = CURVE.n >> _1n + return this.s > HALF + } + normalizeS() { + return this.hasHighS() ? new Signature(this.r, CURVE.n - this.s) : this + } + toDERRawBytes(isCompressed = false) { + return hexToBytes(this.toDERHex(isCompressed)) + } + toDERHex(isCompressed = false) { + const sHex = sliceDER(numberToHexUnpadded(this.s)) + if (isCompressed) return sHex + const rHex = sliceDER(numberToHexUnpadded(this.r)) + const rLen = numberToHexUnpadded(rHex.length / 2) + const sLen = numberToHexUnpadded(sHex.length / 2) + const length = numberToHexUnpadded(rHex.length / 2 + sHex.length / 2 + 4) + return `30${length}02${rLen}${rHex}02${sLen}${sHex}` + } + toRawBytes() { + return this.toDERRawBytes() + } + toHex() { + return this.toDERHex() + } + toCompactRawBytes() { + return hexToBytes(this.toCompactHex()) + } + toCompactHex() { + return numTo32bStr(this.r) + numTo32bStr(this.s) + } + } + function concatBytes(...arrays) { + if (!arrays.every(isUint8a)) throw new Error('Uint8Array list expected') + if (arrays.length === 1) return arrays[0] + const length = arrays.reduce((a, arr) => a + arr.length, 0) + const result = new Uint8Array(length) + for (let i = 0, pad = 0; i < arrays.length; i++) { + const arr = arrays[i] + result.set(arr, pad) + pad += arr.length + } + return result + } + function isUint8a(bytes) { + return bytes instanceof Uint8Array + } + const hexes = Array.from({length: 256}, (v, i) => + i.toString(16).padStart(2, '0') + ) + function bytesToHex(uint8a) { + if (!(uint8a instanceof Uint8Array)) throw new Error('Expected Uint8Array') + let hex = '' + for (let i = 0; i < uint8a.length; i++) { + hex += hexes[uint8a[i]] + } + return hex + } + function numTo32bStr(num) { + if (num > POW_2_256) throw new Error('Expected number < 2^256') + return num.toString(16).padStart(64, '0') + } + function numTo32b(num) { + return hexToBytes(numTo32bStr(num)) + } + function numberToHexUnpadded(num) { + const hex = num.toString(16) + return hex.length & 1 ? `0${hex}` : hex + } + function hexToNumber(hex) { + if (typeof hex !== 'string') { + throw new TypeError('hexToNumber: expected string, got ' + typeof hex) + } + return BigInt(`0x${hex}`) + } + function hexToBytes(hex) { + if (typeof hex !== 'string') { + throw new TypeError('hexToBytes: expected string, got ' + typeof hex) + } + if (hex.length % 2) + throw new Error('hexToBytes: received invalid unpadded hex' + hex.length) + const array = new Uint8Array(hex.length / 2) + for (let i = 0; i < array.length; i++) { + const j = i * 2 + const hexByte = hex.slice(j, j + 2) + const byte = Number.parseInt(hexByte, 16) + if (Number.isNaN(byte) || byte < 0) + throw new Error('Invalid byte sequence') + array[i] = byte + } + return array + } + function bytesToNumber(bytes) { + return hexToNumber(bytesToHex(bytes)) + } + function ensureBytes(hex) { + return hex instanceof Uint8Array ? Uint8Array.from(hex) : hexToBytes(hex) + } + function normalizeScalar(num) { + if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0) + return BigInt(num) + if (typeof num === 'bigint' && isWithinCurveOrder(num)) return num + throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n') + } + function mod(a, b = CURVE.P) { + const result = a % b + return result >= _0n ? result : b + result + } + function pow2(x, power) { + const {P} = CURVE + let res = x + while (power-- > _0n) { + res *= res + res %= P + } + return res + } + function sqrtMod(x) { + const {P} = CURVE + const _6n = BigInt(6) + const _11n = BigInt(11) + const _22n = BigInt(22) + const _23n = BigInt(23) + const _44n = BigInt(44) + const _88n = BigInt(88) + const b2 = (x * x * x) % P + const b3 = (b2 * b2 * x) % P + const b6 = (pow2(b3, _3n) * b3) % P + const b9 = (pow2(b6, _3n) * b3) % P + const b11 = (pow2(b9, _2n) * b2) % P + const b22 = (pow2(b11, _11n) * b11) % P + const b44 = (pow2(b22, _22n) * b22) % P + const b88 = (pow2(b44, _44n) * b44) % P + const b176 = (pow2(b88, _88n) * b88) % P + const b220 = (pow2(b176, _44n) * b44) % P + const b223 = (pow2(b220, _3n) * b3) % P + const t1 = (pow2(b223, _23n) * b22) % P + const t2 = (pow2(t1, _6n) * b2) % P + return pow2(t2, _2n) + } + function invert(number, modulo = CURVE.P) { + if (number === _0n || modulo <= _0n) { + throw new Error( + `invert: expected positive integers, got n=${number} mod=${modulo}` + ) + } + let a = mod(number, modulo) + let b = modulo + let x = _0n, + u = _1n + while (a !== _0n) { + const q = b / a + const r = b % a + const m = x - u * q + ;(b = a), (a = r), (x = u), (u = m) + } + const gcd = b + if (gcd !== _1n) throw new Error('invert: does not exist') + return mod(x, modulo) + } + function invertBatch(nums, p = CURVE.P) { + const scratch = new Array(nums.length) + const lastMultiplied = nums.reduce((acc, num, i) => { + if (num === _0n) return acc + scratch[i] = acc + return mod(acc * num, p) + }, _1n) + const inverted = invert(lastMultiplied, p) + nums.reduceRight((acc, num, i) => { + if (num === _0n) return acc + scratch[i] = mod(acc * scratch[i], p) + return mod(acc * num, p) + }, inverted) + return scratch + } + const divNearest = (a, b) => (a + b / _2n) / b + const POW_2_128 = _2n ** BigInt(128) + function splitScalarEndo(k) { + const {n} = CURVE + const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15') + const b1 = -_1n * BigInt('0xe4437ed6010e88286f547fa90abfe4c3') + const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8') + const b2 = a1 + const c1 = divNearest(b2 * k, n) + const c2 = divNearest(-b1 * k, n) + let k1 = mod(k - c1 * a1 - c2 * a2, n) + let k2 = mod(-c1 * b1 - c2 * b2, n) + const k1neg = k1 > POW_2_128 + const k2neg = k2 > POW_2_128 + if (k1neg) k1 = n - k1 + if (k2neg) k2 = n - k2 + if (k1 > POW_2_128 || k2 > POW_2_128) { + throw new Error('splitScalarEndo: Endomorphism failed, k=' + k) + } + return {k1neg, k1, k2neg, k2} + } + function truncateHash(hash) { + const {n} = CURVE + const byteLength = hash.length + const delta = byteLength * 8 - 256 + let h = bytesToNumber(hash) + if (delta > 0) h = h >> BigInt(delta) + if (h >= n) h -= n + return h + } + class HmacDrbg { + constructor() { + this.v = new Uint8Array(32).fill(1) + this.k = new Uint8Array(32).fill(0) + this.counter = 0 + } + hmac(...values) { + return utils.hmacSha256(this.k, ...values) + } + hmacSync(...values) { + if (typeof utils.hmacSha256Sync !== 'function') + throw new Error('utils.hmacSha256Sync is undefined, you need to set it') + const res = utils.hmacSha256Sync(this.k, ...values) + if (res instanceof Promise) + throw new Error('To use sync sign(), ensure utils.hmacSha256 is sync') + return res + } + incr() { + if (this.counter >= 1000) { + throw new Error('Tried 1,000 k values for sign(), all were invalid') + } + this.counter += 1 + } + async reseed(seed = new Uint8Array()) { + this.k = await this.hmac(this.v, Uint8Array.from([0x00]), seed) + this.v = await this.hmac(this.v) + if (seed.length === 0) return + this.k = await this.hmac(this.v, Uint8Array.from([0x01]), seed) + this.v = await this.hmac(this.v) + } + reseedSync(seed = new Uint8Array()) { + this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed) + this.v = this.hmacSync(this.v) + if (seed.length === 0) return + this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed) + this.v = this.hmacSync(this.v) + } + async generate() { + this.incr() + this.v = await this.hmac(this.v) + return this.v + } + generateSync() { + this.incr() + this.v = this.hmacSync(this.v) + return this.v + } + } + function isWithinCurveOrder(num) { + return _0n < num && num < CURVE.n + } + function isValidFieldElement(num) { + return _0n < num && num < CURVE.P + } + function kmdToSig(kBytes, m, d) { + const k = bytesToNumber(kBytes) + if (!isWithinCurveOrder(k)) return + const {n} = CURVE + const q = Point.BASE.multiply(k) + const r = mod(q.x, n) + if (r === _0n) return + const s = mod(invert(k, n) * mod(m + d * r, n), n) + if (s === _0n) return + const sig = new Signature(r, s) + const recovery = (q.x === sig.r ? 0 : 2) | Number(q.y & _1n) + return {sig, recovery} + } + function normalizePrivateKey(key) { + let num + if (typeof key === 'bigint') { + num = key + } else if ( + typeof key === 'number' && + Number.isSafeInteger(key) && + key > 0 + ) { + num = BigInt(key) + } else if (typeof key === 'string') { + if (key.length !== 64) throw new Error('Expected 32 bytes of private key') + num = hexToNumber(key) + } else if (isUint8a(key)) { + if (key.length !== 32) throw new Error('Expected 32 bytes of private key') + num = bytesToNumber(key) + } else { + throw new TypeError('Expected valid private key') + } + if (!isWithinCurveOrder(num)) + throw new Error('Expected private key: 0 < key < n') + return num + } + function normalizePublicKey(publicKey) { + if (publicKey instanceof Point) { + publicKey.assertValidity() + return publicKey + } else { + return Point.fromHex(publicKey) + } + } + function normalizeSignature(signature) { + if (signature instanceof Signature) { + signature.assertValidity() + return signature + } + try { + return Signature.fromDER(signature) + } catch (error) { + return Signature.fromCompact(signature) + } + } + function getPublicKey(privateKey, isCompressed = false) { + return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed) + } + function recoverPublicKey( + msgHash, + signature, + recovery, + isCompressed = false + ) { + return Point.fromSignature(msgHash, signature, recovery).toRawBytes( + isCompressed + ) + } + function isPub(item) { + const arr = isUint8a(item) + const str = typeof item === 'string' + const len = (arr || str) && item.length + if (arr) return len === 33 || len === 65 + if (str) return len === 66 || len === 130 + if (item instanceof Point) return true + return false + } + function getSharedSecret(privateA, publicB, isCompressed = false) { + if (isPub(privateA)) + throw new TypeError('getSharedSecret: first arg must be private key') + if (!isPub(publicB)) + throw new TypeError('getSharedSecret: second arg must be public key') + const b = normalizePublicKey(publicB) + b.assertValidity() + return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed) + } + function bits2int(bytes) { + const slice = bytes.length > 32 ? bytes.slice(0, 32) : bytes + return bytesToNumber(slice) + } + function bits2octets(bytes) { + const z1 = bits2int(bytes) + const z2 = mod(z1, CURVE.n) + return int2octets(z2 < _0n ? z1 : z2) + } + function int2octets(num) { + if (typeof num !== 'bigint') throw new Error('Expected bigint') + const hex = numTo32bStr(num) + return hexToBytes(hex) + } + function initSigArgs(msgHash, privateKey, extraEntropy) { + if (msgHash == null) + throw new Error(`sign: expected valid message hash, not "${msgHash}"`) + const h1 = ensureBytes(msgHash) + const d = normalizePrivateKey(privateKey) + const seedArgs = [int2octets(d), bits2octets(h1)] + if (extraEntropy != null) { + if (extraEntropy === true) extraEntropy = utils.randomBytes(32) + const e = ensureBytes(extraEntropy) + if (e.length !== 32) + throw new Error('sign: Expected 32 bytes of extra data') + seedArgs.push(e) + } + const seed = concatBytes(...seedArgs) + const m = bits2int(h1) + return {seed, m, d} + } + function finalizeSig(recSig, opts) { + let {sig, recovery} = recSig + const {canonical, der, recovered} = Object.assign( + {canonical: true, der: true}, + opts + ) + if (canonical && sig.hasHighS()) { + sig = sig.normalizeS() + recovery ^= 1 + } + const hashed = der ? sig.toDERRawBytes() : sig.toCompactRawBytes() + return recovered ? [hashed, recovery] : hashed + } + async function sign(msgHash, privKey, opts = {}) { + const {seed, m, d} = initSigArgs(msgHash, privKey, opts.extraEntropy) + let sig + const drbg = new HmacDrbg() + await drbg.reseed(seed) + while (!(sig = kmdToSig(await drbg.generate(), m, d))) await drbg.reseed() + return finalizeSig(sig, opts) + } + function signSync(msgHash, privKey, opts = {}) { + const {seed, m, d} = initSigArgs(msgHash, privKey, opts.extraEntropy) + let sig + const drbg = new HmacDrbg() + drbg.reseedSync(seed) + while (!(sig = kmdToSig(drbg.generateSync(), m, d))) drbg.reseedSync() + return finalizeSig(sig, opts) + } + const vopts = {strict: true} + function verify(signature, msgHash, publicKey, opts = vopts) { + let sig + try { + sig = normalizeSignature(signature) + msgHash = ensureBytes(msgHash) + } catch (error) { + return false + } + const {r, s} = sig + if (opts.strict && sig.hasHighS()) return false + const h = truncateHash(msgHash) + let P + try { + P = normalizePublicKey(publicKey) + } catch (error) { + return false + } + const {n} = CURVE + const sinv = invert(s, n) + const u1 = mod(h * sinv, n) + const u2 = mod(r * sinv, n) + const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2) + if (!R) return false + const v = mod(R.x, n) + return v === r + } + function finalizeSchnorrChallenge(ch) { + return mod(bytesToNumber(ch), CURVE.n) + } + function hasEvenY(point) { + return (point.y & _1n) === _0n + } + class SchnorrSignature { + constructor(r, s) { + this.r = r + this.s = s + this.assertValidity() + } + static fromHex(hex) { + const bytes = ensureBytes(hex) + if (bytes.length !== 64) + throw new TypeError( + `SchnorrSignature.fromHex: expected 64 bytes, not ${bytes.length}` + ) + const r = bytesToNumber(bytes.subarray(0, 32)) + const s = bytesToNumber(bytes.subarray(32, 64)) + return new SchnorrSignature(r, s) + } + assertValidity() { + const {r, s} = this + if (!isValidFieldElement(r) || !isWithinCurveOrder(s)) + throw new Error('Invalid signature') + } + toHex() { + return numTo32bStr(this.r) + numTo32bStr(this.s) + } + toRawBytes() { + return hexToBytes(this.toHex()) + } + } + function schnorrGetPublicKey(privateKey) { + return Point.fromPrivateKey(privateKey).toRawX() + } + function initSchnorrSigArgs(message, privateKey, auxRand) { + if (message == null) + throw new TypeError(`sign: Expected valid message, not "${message}"`) + const m = ensureBytes(message) + const d0 = normalizePrivateKey(privateKey) + const rand = ensureBytes(auxRand) + if (rand.length !== 32) + throw new TypeError('sign: Expected 32 bytes of aux randomness') + const P = Point.fromPrivateKey(d0) + const px = P.toRawX() + const d = hasEvenY(P) ? d0 : CURVE.n - d0 + return {m, P, px, d, rand} + } + function initSchnorrNonce(d, t0h) { + return numTo32b(d ^ bytesToNumber(t0h)) + } + function finalizeSchnorrNonce(k0h) { + const k0 = mod(bytesToNumber(k0h), CURVE.n) + if (k0 === _0n) + throw new Error('sign: Creation of signature failed. k is zero') + const R = Point.fromPrivateKey(k0) + const rx = R.toRawX() + const k = hasEvenY(R) ? k0 : CURVE.n - k0 + return {R, rx, k} + } + function finalizeSchnorrSig(R, k, e, d) { + return new SchnorrSignature(R.x, mod(k + e * d, CURVE.n)).toRawBytes() + } + async function schnorrSign( + message, + privateKey, + auxRand = utils.randomBytes() + ) { + const {m, px, d, rand} = initSchnorrSigArgs(message, privateKey, auxRand) + const t = initSchnorrNonce(d, await utils.taggedHash(TAGS.aux, rand)) + const {R, rx, k} = finalizeSchnorrNonce( + await utils.taggedHash(TAGS.nonce, t, px, m) + ) + const e = finalizeSchnorrChallenge( + await utils.taggedHash(TAGS.challenge, rx, px, m) + ) + const sig = finalizeSchnorrSig(R, k, e, d) + const isValid = await schnorrVerify(sig, m, px) + if (!isValid) throw new Error('sign: Invalid signature produced') + return sig + } + function schnorrSignSync(message, privateKey, auxRand = utils.randomBytes()) { + const {m, px, d, rand} = initSchnorrSigArgs(message, privateKey, auxRand) + const t = initSchnorrNonce(d, utils.taggedHashSync(TAGS.aux, rand)) + const {R, rx, k} = finalizeSchnorrNonce( + utils.taggedHashSync(TAGS.nonce, t, px, m) + ) + const e = finalizeSchnorrChallenge( + utils.taggedHashSync(TAGS.challenge, rx, px, m) + ) + const sig = finalizeSchnorrSig(R, k, e, d) + const isValid = schnorrVerifySync(sig, m, px) + if (!isValid) throw new Error('sign: Invalid signature produced') + return sig + } + function initSchnorrVerify(signature, message, publicKey) { + const raw = signature instanceof SchnorrSignature + const sig = raw ? signature : SchnorrSignature.fromHex(signature) + if (raw) sig.assertValidity() + return { + ...sig, + m: ensureBytes(message), + P: normalizePublicKey(publicKey) + } + } + function finalizeSchnorrVerify(r, P, s, e) { + const R = Point.BASE.multiplyAndAddUnsafe( + P, + normalizePrivateKey(s), + mod(-e, CURVE.n) + ) + if (!R || !hasEvenY(R) || R.x !== r) return false + return true + } + async function schnorrVerify(signature, message, publicKey) { + try { + const {r, s, m, P} = initSchnorrVerify(signature, message, publicKey) + const e = finalizeSchnorrChallenge( + await utils.taggedHash(TAGS.challenge, numTo32b(r), P.toRawX(), m) + ) + return finalizeSchnorrVerify(r, P, s, e) + } catch (error) { + return false + } + } + function schnorrVerifySync(signature, message, publicKey) { + try { + const {r, s, m, P} = initSchnorrVerify(signature, message, publicKey) + const e = finalizeSchnorrChallenge( + utils.taggedHashSync(TAGS.challenge, numTo32b(r), P.toRawX(), m) + ) + return finalizeSchnorrVerify(r, P, s, e) + } catch (error) { + return false + } + } + const schnorr = { + Signature: SchnorrSignature, + getPublicKey: schnorrGetPublicKey, + sign: schnorrSign, + verify: schnorrVerify, + signSync: schnorrSignSync, + verifySync: schnorrVerifySync + } + Point.BASE._setWindowSize(8) + const crypto = { + node: nodeCrypto, + web: typeof self === 'object' && 'crypto' in self ? self.crypto : undefined + } + const TAGS = { + challenge: 'BIP0340/challenge', + aux: 'BIP0340/aux', + nonce: 'BIP0340/nonce' + } + const TAGGED_HASH_PREFIXES = {} + const utils = { + isValidPrivateKey(privateKey) { + try { + normalizePrivateKey(privateKey) + return true + } catch (error) { + return false + } + }, + privateAdd: (privateKey, tweak) => { + const p = normalizePrivateKey(privateKey) + const t = normalizePrivateKey(tweak) + return numTo32b(mod(p + t, CURVE.n)) + }, + privateNegate: privateKey => { + const p = normalizePrivateKey(privateKey) + return numTo32b(CURVE.n - p) + }, + pointAddScalar: (p, tweak, isCompressed) => { + const P = Point.fromHex(p) + const t = normalizePrivateKey(tweak) + const Q = Point.BASE.multiplyAndAddUnsafe(P, t, _1n) + if (!Q) throw new Error('Tweaked point at infinity') + return Q.toRawBytes(isCompressed) + }, + pointMultiply: (p, tweak, isCompressed) => { + const P = Point.fromHex(p) + const t = bytesToNumber(ensureBytes(tweak)) + return P.multiply(t).toRawBytes(isCompressed) + }, + hashToPrivateKey: hash => { + hash = ensureBytes(hash) + if (hash.length < 40 || hash.length > 1024) + throw new Error('Expected 40-1024 bytes of private key as per FIPS 186') + const num = mod(bytesToNumber(hash), CURVE.n - _1n) + _1n + return numTo32b(num) + }, + randomBytes: (bytesLength = 32) => { + if (crypto.web) { + return crypto.web.getRandomValues(new Uint8Array(bytesLength)) + } else if (crypto.node) { + const {randomBytes} = crypto.node + return Uint8Array.from(randomBytes(bytesLength)) + } else { + throw new Error("The environment doesn't have randomBytes function") + } + }, + randomPrivateKey: () => { + return utils.hashToPrivateKey(utils.randomBytes(40)) + }, + bytesToHex, + hexToBytes, + concatBytes, + mod, + invert, + sha256: async (...messages) => { + if (crypto.web) { + const buffer = await crypto.web.subtle.digest( + 'SHA-256', + concatBytes(...messages) + ) + return new Uint8Array(buffer) + } else if (crypto.node) { + const {createHash} = crypto.node + const hash = createHash('sha256') + messages.forEach(m => hash.update(m)) + return Uint8Array.from(hash.digest()) + } else { + throw new Error("The environment doesn't have sha256 function") + } + }, + hmacSha256: async (key, ...messages) => { + if (crypto.web) { + const ckey = await crypto.web.subtle.importKey( + 'raw', + key, + {name: 'HMAC', hash: {name: 'SHA-256'}}, + false, + ['sign'] + ) + const message = concatBytes(...messages) + const buffer = await crypto.web.subtle.sign('HMAC', ckey, message) + return new Uint8Array(buffer) + } else if (crypto.node) { + const {createHmac} = crypto.node + const hash = createHmac('sha256', key) + messages.forEach(m => hash.update(m)) + return Uint8Array.from(hash.digest()) + } else { + throw new Error("The environment doesn't have hmac-sha256 function") + } + }, + sha256Sync: undefined, + hmacSha256Sync: undefined, + taggedHash: async (tag, ...messages) => { + let tagP = TAGGED_HASH_PREFIXES[tag] + if (tagP === undefined) { + const tagH = await utils.sha256( + Uint8Array.from(tag, c => c.charCodeAt(0)) + ) + tagP = concatBytes(tagH, tagH) + TAGGED_HASH_PREFIXES[tag] = tagP + } + return utils.sha256(tagP, ...messages) + }, + taggedHashSync: (tag, ...messages) => { + if (typeof utils.sha256Sync !== 'function') + throw new Error('utils.sha256Sync is undefined, you need to set it') + let tagP = TAGGED_HASH_PREFIXES[tag] + if (tagP === undefined) { + const tagH = utils.sha256Sync( + Uint8Array.from(tag, c => c.charCodeAt(0)) + ) + tagP = concatBytes(tagH, tagH) + TAGGED_HASH_PREFIXES[tag] = tagP + } + return utils.sha256Sync(tagP, ...messages) + }, + precompute(windowSize = 8, point = Point.BASE) { + const cached = point === Point.BASE ? point : new Point(point.x, point.y) + cached._setWindowSize(windowSize) + cached.multiply(_3n) + return cached + } + } + + exports.CURVE = CURVE + exports.Point = Point + exports.Signature = Signature + exports.getPublicKey = getPublicKey + exports.getSharedSecret = getSharedSecret + exports.recoverPublicKey = recoverPublicKey + exports.schnorr = schnorr + exports.sign = sign + exports.signSync = signSync + exports.utils = utils + exports.verify = verify + + Object.defineProperty(exports, '__esModule', {value: true}) +}) diff --git a/lnbits/extensions/cashu/static/js/utils.js b/lnbits/extensions/cashu/static/js/utils.js new file mode 100644 index 000000000..cf852b58b --- /dev/null +++ b/lnbits/extensions/cashu/static/js/utils.js @@ -0,0 +1,23 @@ +function splitAmount(value) { + const chunks = [] + for (let i = 0; i < 32; i++) { + const mask = 1 << i + if ((value & mask) !== 0) chunks.push(Math.pow(2, i)) + } + return chunks +} + +function bytesToNumber(bytes) { + return hexToNumber(nobleSecp256k1.utils.bytesToHex(bytes)) +} + +function bigIntStringify(key, value) { + return typeof value === 'bigint' ? value.toString() : value +} + +function hexToNumber(hex) { + if (typeof hex !== 'string') { + throw new TypeError('hexToNumber: expected string, got ' + typeof hex) + } + return BigInt(`0x${hex}`) +} diff --git a/lnbits/extensions/cashu/tasks.py b/lnbits/extensions/cashu/tasks.py new file mode 100644 index 000000000..9de17a1cf --- /dev/null +++ b/lnbits/extensions/cashu/tasks.py @@ -0,0 +1,33 @@ +import asyncio +import json + +from cashu.core.migrations import migrate_databases +from cashu.mint import migrations + +from lnbits.core.models import Payment +from lnbits.tasks import register_invoice_listener + +from . import db, ledger +from .crud import get_cashu + + +async def startup_cashu_mint(): + await migrate_databases(db, migrations) + await ledger.load_used_proofs() + await ledger.init_keysets(autosave=False) + pass + + +async def wait_for_paid_invoices(): + invoice_queue = asyncio.Queue() + register_invoice_listener(invoice_queue) + + while True: + payment = await invoice_queue.get() + await on_invoice_paid(payment) + + +async def on_invoice_paid(payment: Payment) -> None: + if payment.extra and not payment.extra.get("tag") == "cashu": + return + return diff --git a/lnbits/extensions/cashu/templates/cashu/_api_docs.html b/lnbits/extensions/cashu/templates/cashu/_api_docs.html new file mode 100644 index 000000000..f7bb19f60 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/_api_docs.html @@ -0,0 +1,80 @@ + + + + diff --git a/lnbits/extensions/cashu/templates/cashu/_cashu.html b/lnbits/extensions/cashu/templates/cashu/_cashu.html new file mode 100644 index 000000000..952fe7e1a --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/_cashu.html @@ -0,0 +1,13 @@ + + + +

Create Cashu ecash mints and wallets.

+ Created by + arcbtc, + vlad, + calle. +
+
+
diff --git a/lnbits/extensions/cashu/templates/cashu/index.html b/lnbits/extensions/cashu/templates/cashu/index.html new file mode 100644 index 000000000..2599669cf --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/index.html @@ -0,0 +1,367 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} +
+
+ + + Cashu mint and wallet +

+

+ Here you can create multiple cashu mints that you can share. Each mint + can service many users but all ecash tokens of a mint are only valid + inside that mint and not across different mints. To exchange funds + between mints, use Lightning payments. +

+ Important +

+

+ If you are the operator of this LNbits instance, make sure to set + CASHU_PRIVATE_KEY="randomkey" in your configuration file. Do not + create mints before setting the key and do not change the key once + set. +

+
+
+ + + +
+
+
Mints
+
+
+ Export to CSV +
+
+ + {% raw %} + + + + {% endraw %} + + New Mint +
+
+
+ +
+ + +
{{SITE_TITLE}} Cashu extension
+
+ + + + {% include "cashu/_api_docs.html" %} + + {% include "cashu/_cashu.html" %} + + +
+
+ + + + + + + +
+ Create Mint + + Cancel +
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} diff --git a/lnbits/extensions/cashu/templates/cashu/mint.html b/lnbits/extensions/cashu/templates/cashu/mint.html new file mode 100644 index 000000000..ee6ab606c --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/mint.html @@ -0,0 +1,76 @@ +{% extends "public.html" %} {% block page %} +
+
+ + +
+ +

{{ mint_name }}

+ Open wallet +
+
+
+ + +
Read the following carefully!
+

+ This is a + Cashu + mint. Cashu is an ecash system for Bitcoin. +

+

+ Open this page in your native browser
+ Before you continue to the wallet, make sure to open this page in your + device's native browser application (Safari for iOS, Chrome for + Android). Do not use Cashu in an embedded browser that opens when you + click a link in a messenger. +

+

+ Add wallet to home screen
+ You can add Cashu to your home screen as a progressive web app (PWA). + After opening the wallet in your browser (click the link above), on + Android (Chrome), click the menu at the upper right. On iOS (Safari), + click the share button. Now press the Add to Home screen button. +

+

+ Backup your wallet
+ Ecash is a bearer asset. That means losing access to your wallet will + make you lose your funds. The wallet stores ecash tokens on your + device's database. If you lose the link or delete your your data + without backing up, you will lose your tokens. Press the Backup button + in the wallet to download a copy of your tokens. +

+

+ This service is in BETA
+ We hold no responsibility for people losing access to funds. Use at + your own risk! +

+
+
+
+ + {% endblock %} {% block scripts %} + + + + {% endblock %} +
diff --git a/lnbits/extensions/cashu/templates/cashu/wallet.html b/lnbits/extensions/cashu/templates/cashu/wallet.html new file mode 100644 index 000000000..a133f5920 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/wallet.html @@ -0,0 +1,2337 @@ +{% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Cashu +{% endraw %} {% endblock %} {% block footer %}{% endblock %} {% block +page_container %} + + +
+
+ + +
+
+
+ Get invoice + +
+
+

+
+ {% raw %} {{getBalance()}} + {{tickershort}}{% endraw %} +
+

+
+
+ Pay invoice + +
+
+
+
+
+
+

+
+ {% raw %} {{getBalance()}} + {{tickershort}}{% endraw %} +
+

+
+
+
+
+
+ + + +
+
+ Get Ecash +
+
+
+ + Pay Ecash +
+
+ + + + + + + + + + + + + {% raw %} + + {% endraw %} + + + + + + + + {% raw %} + + {% endraw %} + + + + + + + + {% raw %} + + {% endraw %} + + + +
+
+ +
+ + Warning + BackupDownload wallet backup +
+
+ + + + + + + + + + + + +
+
+ {% raw %} {{ + parseFloat(String(payInvoiceData.invoice.fsat).replaceAll(",", + "")) / 100 }} {% endraw %} {{LNBITS_DENOMINATION}} {% raw %} +
+
+ {{ payInvoiceData.invoice.fsat }}{% endraw %} + {{LNBITS_DENOMINATION}} {% raw %} +
+ +

+ Description: {{ + payInvoiceData.invoice.description }}
+ Expire date: {{ payInvoiceData.invoice.expireDate + }}
+ Hash: {{ payInvoiceData.invoice.hash }} +

+ {% endraw %} +
+ Pay + Cancel +
+
+ Not enough funds! + Cancel +
+
+
+ {% raw %} + +

+ Authenticate with {{ payInvoiceData.lnurlauth.domain }}? +

+ +

+ For every website and for every LNbits wallet, a new keypair + will be deterministically generated so your identity can't be + tied to your LNbits wallet or linked across websites. No other + data will be shared with {{ payInvoiceData.lnurlauth.domain }}. +

+

+ Your public key for + {{ payInvoiceData.lnurlauth.domain }} is: +

+

+ + {{ payInvoiceData.lnurlauth.pubkey }} + +

+
+ Login + Cancel +
+
+ {% endraw %} +
+
+ {% raw %} + +

+ {{ payInvoiceData.lnurlpay.domain }} is requesting {{ + payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }} + {{LNBITS_DENOMINATION}} + +
+ and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment +
+

+

+ {{ payInvoiceData.lnurlpay.targetUser || + payInvoiceData.lnurlpay.domain }} + is requesting
+ between + {{ payInvoiceData.lnurlpay.minSendable | msatoshiFormat }} + and + {{ payInvoiceData.lnurlpay.maxSendable | msatoshiFormat }} + {% endraw %} {{LNBITS_DENOMINATION}} {% raw %} + +
+ and a {{payInvoiceData.lnurlpay.commentAllowed}}-char comment +
+

+ +
+

+ {{ payInvoiceData.lnurlpay.description }} +

+

+ +

+
+
+
+ {% endraw %} + + {% raw %} +
+
+ +
+
+
+ Send {{LNBITS_DENOMINATION}} + Cancel +
+
+ {% endraw %} +
+
+ + + +
+ Enter + + + Close +
+
+
+ + + +
+ + Cancel + +
+
+
+
+
+ + + +
+ +
+
+ Cancel +
+
+
+ + + +
Warning
+

+ Bookmark this page and backup your tokens! + Ecash is a bearer asset, meaning losing access to this wallet will + mean you will lose the funds. This wallet stores ecash tokens in its + database. If you lose the link or delete your your data without + backing up, you will lose your tokens. Press the Backup button to + download a copy of your tokens. +

+

+ Add to home screen. + You can add Cashu to your home screen as a progressive web app + (PWA). On Android Chrome, click the hamburger menu at the upper + right. On iOS Safari, click the share button. Now press the Add to + Home screen button. +

+

+ This service is in BETA! We hold no responsibility + for people losing access to funds. Use at your own risk! +

+
+ Copy wallet URL + I understand +
+
+
+ + + +
+
+
+ Create a Lightning invoice +
+
+ + +
+ +
+ Copy invoice + Create Invoice + Close +
+
+
+ + + +
+
+
+ How much would you like to send? +
+
+ + +
+
+
+ + + + + + +
+ +
+
+ Send Tokens + +
+ Copy token + Copy link +
+ + Close +
+
+
+ + + +
+
+
+ Receive Cashu tokens +
+
+ +
+ +
+ Receive Tokens + + Close +
+
+
+
+
+
+{% endblock %} {% block styles %} + +{% endblock %} {% block scripts %} + + + + + +{% endblock %} diff --git a/lnbits/extensions/cashu/views.py b/lnbits/extensions/cashu/views.py new file mode 100644 index 000000000..0de791c40 --- /dev/null +++ b/lnbits/extensions/cashu/views.py @@ -0,0 +1,224 @@ +from http import HTTPStatus + +from fastapi import Request +from fastapi.params import Depends +from fastapi.templating import Jinja2Templates +from starlette.exceptions import HTTPException +from starlette.responses import HTMLResponse + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import cashu_ext, cashu_renderer +from .crud import get_cashu + +templates = Jinja2Templates(directory="templates") + + +@cashu_ext.get("/", response_class=HTMLResponse) +async def index( + request: Request, + user: User = Depends(check_user_exists), # type: ignore +): + return cashu_renderer().TemplateResponse( + "cashu/index.html", {"request": request, "user": user.dict()} + ) + + +@cashu_ext.get("/wallet") +async def wallet(request: Request, mint_id: str): + return cashu_renderer().TemplateResponse( + "cashu/wallet.html", + { + "request": request, + "web_manifest": f"/cashu/manifest/{mint_id}.webmanifest", + }, + ) + + +@cashu_ext.get("/mint/{mintID}") +async def cashu(request: Request, mintID): + cashu = await get_cashu(mintID) + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + return cashu_renderer().TemplateResponse( + "cashu/mint.html", + {"request": request, "mint_name": cashu.name, "mint_id": mintID}, + ) + + +@cashu_ext.get("/manifest/{cashu_id}.webmanifest") +async def manifest(cashu_id: str): + cashu = await get_cashu(cashu_id) + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + + return { + "short_name": "Cashu", + "name": "Cashu" + " - " + cashu.name, + "icons": [ + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-512-512.png", + "type": "image/png", + "sizes": "512x512", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-96-96.png", + "type": "image/png", + "sizes": "96x96", + }, + ], + "id": "/cashu/wallet?mint_id=" + cashu_id, + "start_url": "/cashu/wallet?mint_id=" + cashu_id, + "background_color": "#1F2234", + "description": "Cashu ecash wallet", + "display": "standalone", + "scope": "/cashu/", + "theme_color": "#1F2234", + "protocol_handlers": [ + {"protocol": "cashu", "url": "&recv_token=%s"}, + {"protocol": "lightning", "url": "&lightning=%s"}, + ], + "shortcuts": [ + { + "name": "Cashu" + " - " + cashu.name, + "short_name": "Cashu", + "description": "Cashu" + " - " + cashu.name, + "url": "/cashu/wallet?mint_id=" + cashu_id, + "icons": [ + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-512-512.png", + "sizes": "512x512", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-192-192.png", + "sizes": "192x192", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-144-144.png", + "sizes": "144x144", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-96-96.png", + "sizes": "96x96", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-72-72.png", + "sizes": "72x72", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/android/android-launchericon-48-48.png", + "sizes": "48x48", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/16.png", + "sizes": "16x16", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/20.png", + "sizes": "20x20", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/29.png", + "sizes": "29x29", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/32.png", + "sizes": "32x32", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/40.png", + "sizes": "40x40", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/50.png", + "sizes": "50x50", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/57.png", + "sizes": "57x57", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/58.png", + "sizes": "58x58", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/60.png", + "sizes": "60x60", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/64.png", + "sizes": "64x64", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/72.png", + "sizes": "72x72", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/76.png", + "sizes": "76x76", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/80.png", + "sizes": "80x80", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/87.png", + "sizes": "87x87", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/100.png", + "sizes": "100x100", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/114.png", + "sizes": "114x114", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/120.png", + "sizes": "120x120", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/128.png", + "sizes": "128x128", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/144.png", + "sizes": "144x144", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/152.png", + "sizes": "152x152", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/167.png", + "sizes": "167x167", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/180.png", + "sizes": "180x180", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/192.png", + "sizes": "192x192", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/256.png", + "sizes": "256x256", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/512.png", + "sizes": "512x512", + }, + { + "src": "https://github.com/cashubtc/cashu-ui/raw/main/ui/icons/circle/ios/1024.png", + "sizes": "1024x1024", + }, + ], + } + ], + } diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py new file mode 100644 index 000000000..ad253abf0 --- /dev/null +++ b/lnbits/extensions/cashu/views_api.py @@ -0,0 +1,382 @@ +import json +import math +from http import HTTPStatus +from typing import Dict, List, Union + +import httpx + +# -------- cashu imports +from cashu.core.base import ( + BlindedSignature, + CheckFeesRequest, + CheckFeesResponse, + CheckRequest, + GetMeltResponse, + GetMintResponse, + Invoice, + MeltRequest, + MintRequest, + PostSplitResponse, + Proof, + SplitRequest, +) +from fastapi import Query +from fastapi.params import Depends +from lnurl import decode as decode_lnurl +from loguru import logger +from secp256k1 import PublicKey +from starlette.exceptions import HTTPException + +from lnbits import bolt11 +from lnbits.core.crud import check_internal, get_user +from lnbits.core.services import ( + check_transaction_status, + create_invoice, + fee_reserve, + pay_invoice, +) +from lnbits.core.views.api import api_payment +from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key +from lnbits.helpers import urlsafe_short_hash +from lnbits.wallets.base import PaymentStatus + +from . import cashu_ext, ledger +from .crud import create_cashu, delete_cashu, get_cashu, get_cashus +from .models import Cashu + +# --------- extension imports + + +LIGHTNING = True + +######################################## +############### LNBITS MINTS ########### +######################################## + + +@cashu_ext.get("/api/v1/mints", status_code=HTTPStatus.OK) +async def api_cashus( + all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore +): + """ + Get all mints of this wallet. + """ + wallet_ids = [wallet.wallet.id] + if all_wallets: + user = await get_user(wallet.wallet.user) + if user: + wallet_ids = user.wallet_ids + + return [cashu.dict() for cashu in await get_cashus(wallet_ids)] + + +@cashu_ext.post("/api/v1/mints", status_code=HTTPStatus.CREATED) +async def api_cashu_create( + data: Cashu, + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore +): + """ + Create a new mint for this wallet. + """ + cashu_id = urlsafe_short_hash() + # generate a new keyset in cashu + keyset = await ledger.load_keyset(cashu_id) + + cashu = await create_cashu( + cashu_id=cashu_id, keyset_id=keyset.id, wallet_id=wallet.wallet.id, data=data + ) + logger.debug(cashu) + return cashu.dict() + + +@cashu_ext.delete("/api/v1/mints/{cashu_id}") +async def api_cashu_delete( + cashu_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) # type: ignore +): + """ + Delete an existing cashu mint. + """ + cashu = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Cashu mint does not exist." + ) + + if cashu.wallet != wallet.wallet.id: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, detail="Not your Cashu mint." + ) + + await delete_cashu(cashu_id) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + + +####################################### +########### CASHU ENDPOINTS ########### +####################################### + + +@cashu_ext.get("/api/v1/{cashu_id}/keys", status_code=HTTPStatus.OK) +async def keys(cashu_id: str = Query(None)) -> dict[int, str]: + """Get the public keys of the mint""" + cashu: Union[Cashu, None] = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + + return ledger.get_keyset(keyset_id=cashu.keyset_id) + + +@cashu_ext.get("/api/v1/{cashu_id}/keysets", status_code=HTTPStatus.OK) +async def keysets(cashu_id: str = Query(None)) -> dict[str, list[str]]: + """Get the public keys of the mint""" + cashu: Union[Cashu, None] = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + + return {"keysets": [cashu.keyset_id]} + + +@cashu_ext.get("/api/v1/{cashu_id}/mint") +async def request_mint(cashu_id: str = Query(None), amount: int = 0) -> GetMintResponse: + """ + Request minting of new tokens. The mint responds with a Lightning invoice. + This endpoint can be used for a Lightning invoice UX flow. + + Call `POST /mint` after paying the invoice. + """ + cashu: Union[Cashu, None] = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + + # create an invoice that the wallet needs to pay + try: + payment_hash, payment_request = await create_invoice( + wallet_id=cashu.wallet, + amount=amount, + memo=f"{cashu.name}", + extra={"tag": "cashu"}, + ) + invoice = Invoice( + amount=amount, pr=payment_request, hash=payment_hash, issued=False + ) + # await store_lightning_invoice(cashu_id, invoice) + await ledger.crud.store_lightning_invoice(invoice=invoice, db=ledger.db) + except Exception as e: + logger.error(e) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) + + print(f"Lightning invoice: {payment_request}") + resp = GetMintResponse(pr=payment_request, hash=payment_hash) + # return {"pr": payment_request, "hash": payment_hash} + return resp + + +@cashu_ext.post("/api/v1/{cashu_id}/mint") +async def mint_coins( + data: MintRequest, + cashu_id: str = Query(None), + payment_hash: str = Query(None), +) -> List[BlindedSignature]: + """ + Requests the minting of tokens belonging to a paid payment request. + Call this endpoint after `GET /mint`. + """ + cashu: Union[Cashu, None] = await get_cashu(cashu_id) + if cashu is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + + if LIGHTNING: + invoice: Invoice = await ledger.crud.get_lightning_invoice( + db=ledger.db, hash=payment_hash + ) + if invoice is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Mint does not know this invoice.", + ) + if invoice.issued == True: + raise HTTPException( + status_code=HTTPStatus.PAYMENT_REQUIRED, + detail="Tokens already issued for this invoice.", + ) + + total_requested = sum([bm.amount for bm in data.blinded_messages]) + if total_requested > invoice.amount: + raise HTTPException( + status_code=HTTPStatus.PAYMENT_REQUIRED, + detail=f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}", + ) + + status: PaymentStatus = await check_transaction_status(cashu.wallet, payment_hash) + + if status.paid != True: + raise HTTPException( + status_code=HTTPStatus.PAYMENT_REQUIRED, detail="Invoice not paid." + ) + try: + keyset = ledger.keysets.keysets[cashu.keyset_id] + + promises = await ledger._generate_promises( + B_s=data.blinded_messages, keyset=keyset + ) + assert len(promises), HTTPException( + status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="No promises returned." + ) + await ledger.crud.update_lightning_invoice( + db=ledger.db, hash=payment_hash, issued=True + ) + + return promises + except Exception as e: + logger.error(e) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) + + +@cashu_ext.post("/api/v1/{cashu_id}/melt") +async def melt_coins( + payload: MeltRequest, cashu_id: str = Query(None) +) -> GetMeltResponse: + """Invalidates proofs and pays a Lightning invoice.""" + cashu: Union[None, Cashu] = await get_cashu(cashu_id) + if cashu is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + proofs = payload.proofs + invoice = payload.invoice + + # !!!!!!! MAKE SURE THAT PROOFS ARE ONLY FROM THIS CASHU KEYSET ID + # THIS IS NECESSARY BECAUSE THE CASHU BACKEND WILL ACCEPT ANY VALID + # TOKENS + assert all([p.id == cashu.keyset_id for p in proofs]), HTTPException( + status_code=HTTPStatus.METHOD_NOT_ALLOWED, + detail="Error: Tokens are from another mint.", + ) + + assert all([ledger._verify_proof(p) for p in proofs]), HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail="Could not verify proofs.", + ) + + total_provided = sum([p["amount"] for p in proofs]) + invoice_obj = bolt11.decode(invoice) + amount = math.ceil(invoice_obj.amount_msat / 1000) + + internal_checking_id = await check_internal(invoice_obj.payment_hash) + + if not internal_checking_id: + fees_msat = fee_reserve(invoice_obj.amount_msat) + else: + fees_msat = 0 + assert total_provided >= amount + fees_msat / 1000, Exception( + f"Provided proofs ({total_provided} sats) not enough for Lightning payment ({amount + fees_msat} sats)." + ) + + await pay_invoice( + wallet_id=cashu.wallet, + payment_request=invoice, + description=f"pay cashu invoice", + extra={"tag": "cashu", "cahsu_name": cashu.name}, + ) + + status: PaymentStatus = await check_transaction_status( + cashu.wallet, invoice_obj.payment_hash + ) + if status.paid == True: + await ledger._invalidate_proofs(proofs) + return GetMeltResponse(paid=status.paid, preimage=status.preimage) + + +@cashu_ext.post("/api/v1/{cashu_id}/check") +async def check_spendable( + payload: CheckRequest, cashu_id: str = Query(None) +) -> Dict[int, bool]: + """Check whether a secret has been spent already or not.""" + cashu: Union[None, Cashu] = await get_cashu(cashu_id) + if cashu is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + return await ledger.check_spendable(payload.proofs) + + +@cashu_ext.post("/api/v1/{cashu_id}/checkfees") +async def check_fees( + payload: CheckFeesRequest, cashu_id: str = Query(None) +) -> CheckFeesResponse: + """ + Responds with the fees necessary to pay a Lightning invoice. + Used by wallets for figuring out the fees they need to supply. + This is can be useful for checking whether an invoice is internal (Cashu-to-Cashu). + """ + cashu: Union[None, Cashu] = await get_cashu(cashu_id) + if cashu is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + invoice_obj = bolt11.decode(payload.pr) + internal_checking_id = await check_internal(invoice_obj.payment_hash) + + if not internal_checking_id: + fees_msat = fee_reserve(invoice_obj.amount_msat) + else: + fees_msat = 0 + return CheckFeesResponse(fee=fees_msat / 1000) + + +@cashu_ext.post("/api/v1/{cashu_id}/split") +async def split( + payload: SplitRequest, cashu_id: str = Query(None) +) -> PostSplitResponse: + """ + Requetst a set of tokens with amount "total" to be split into two + newly minted sets with amount "split" and "total-split". + """ + cashu: Union[None, Cashu] = await get_cashu(cashu_id) + if cashu is None: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist." + ) + proofs = payload.proofs + + # !!!!!!! MAKE SURE THAT PROOFS ARE ONLY FROM THIS CASHU KEYSET ID + # THIS IS NECESSARY BECAUSE THE CASHU BACKEND WILL ACCEPT ANY VALID + # TOKENS + if not all([p.id == cashu.keyset_id for p in proofs]): + raise HTTPException( + status_code=HTTPStatus.METHOD_NOT_ALLOWED, + detail="Error: Tokens are from another mint.", + ) + + amount = payload.amount + outputs = payload.outputs.blinded_messages + assert outputs, Exception("no outputs provided.") + split_return = None + try: + keyset = ledger.keysets.keysets[cashu.keyset_id] + split_return = await ledger.split(proofs, amount, outputs, keyset) + except Exception as exc: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(exc), + ) + if not split_return: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail="there was an error with the split", + ) + frst_promises, scnd_promises = split_return + resp = PostSplitResponse(fst=frst_promises, snd=scnd_promises) + return resp diff --git a/lnbits/helpers.py b/lnbits/helpers.py index 838761603..9042ece06 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -20,6 +20,8 @@ class Extension(NamedTuple): icon: Optional[str] = None contributors: Optional[List[str]] = None hidden: bool = False + migration_module: Optional[str] = None + db_name: Optional[str] = None class ExtensionManager: @@ -66,6 +68,8 @@ class ExtensionManager: config.get("icon"), config.get("contributors"), config.get("hidden") or False, + config.get("migration_module"), + config.get("db_name"), ) ) diff --git a/poetry.lock b/poetry.lock index 5b283d758..1df342c99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,7 +8,7 @@ python-versions = ">=3.6,<4.0" [[package]] name = "anyio" -version = "3.6.1" +version = "3.6.2" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "main" optional = false @@ -22,7 +22,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] -trio = ["trio (>=0.16)"] +trio = ["trio (>=0.16,<0.22)"] [[package]] name = "asgiref" @@ -59,17 +59,17 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} [[package]] name = "attrs" -version = "21.2.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] [[package]] name = "base58" @@ -100,11 +100,11 @@ python-versions = "*" [[package]] name = "black" -version = "22.8.0" +version = "22.10.0" description = "The uncompromising code formatter." category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" @@ -121,6 +121,60 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cashu" +version = "0.5.4" +description = "Ecash wallet and mint with Bitcoin Lightning support" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +anyio = {version = "3.6.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +attrs = {version = "22.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +bech32 = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +bitstring = {version = "3.1.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +certifi = {version = "2022.9.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +cffi = {version = "1.15.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +charset-normalizer = {version = "2.0.12", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +click = {version = "8.0.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +colorama = {version = "0.4.5", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and platform_system == \"Windows\" or python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""} +ecdsa = {version = "0.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +environs = {version = "9.5.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +fastapi = {version = "0.83.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +h11 = {version = "0.12.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +idna = {version = "3.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +importlib-metadata = {version = "5.0.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} +iniconfig = {version = "1.1.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +loguru = {version = "0.6.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +marshmallow = {version = "3.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +outcome = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +packaging = {version = "21.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pluggy = {version = "1.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +py = {version = "1.11.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pycparser = {version = "2.21", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pydantic = {version = "1.10.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pyparsing = {version = "3.0.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pysocks = {version = "1.7.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pytest = {version = "7.1.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pytest-asyncio = {version = "0.19.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +python-bitcoinlib = {version = "0.11.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +python-dotenv = {version = "0.21.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +represent = {version = "1.6.0.post0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +requests = {version = "2.27.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +secp256k1 = {version = "0.14.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +six = {version = "1.16.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +sniffio = {version = "1.3.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +sqlalchemy = {version = "1.3.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +sqlalchemy-aio = {version = "0.17.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +starlette = {version = "0.19.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +tomli = {version = "2.0.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +typing-extensions = {version = "4.4.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +urllib3 = {version = "1.26.12", markers = "python_version >= \"3.7\" and python_version < \"4\""} +uvicorn = {version = "0.18.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +win32-setctime = {version = "1.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""} +zipp = {version = "3.9.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} + [[package]] name = "Cerberus" version = "1.3.4" @@ -134,15 +188,15 @@ setuptools = "*" [[package]] name = "certifi" -version = "2021.5.30" +version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "cffi" -version = "1.15.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -153,7 +207,7 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.0.6" +version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -164,7 +218,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.1" +version = "8.0.4" description = "Composable command line interface toolkit" category = "main" optional = false @@ -229,7 +283,7 @@ test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0 [[package]] name = "ecdsa" -version = "0.17.0" +version = "0.18.0" description = "ECDSA cryptographic signature library (pure python)" category = "main" optional = false @@ -260,7 +314,7 @@ python-versions = "*" [[package]] name = "environs" -version = "9.3.3" +version = "9.5.0" description = "simplified environment variable parsing" category = "main" optional = false @@ -271,14 +325,14 @@ marshmallow = ">=3.0.0" python-dotenv = "*" [package.extras] -dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] +dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] django = ["dj-database-url", "dj-email-url", "django-cache-url"] -lint = ["flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] +lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] [[package]] name = "fastapi" -version = "0.78.0" +version = "0.83.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -290,13 +344,13 @@ starlette = "0.19.1" [package.extras] all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] [[package]] name = "grpcio" -version = "1.49.1" +version = "1.50.0" description = "HTTP/2-based RPC framework" category = "main" optional = false @@ -306,7 +360,7 @@ python-versions = ">=3.7" six = ">=1.5.2" [package.extras] -protobuf = ["grpcio-tools (>=1.49.1)"] +protobuf = ["grpcio-tools (>=1.50.0)"] [[package]] name = "h11" @@ -367,7 +421,7 @@ socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" -version = "3.2" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -375,26 +429,26 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.8.1" +version = "5.0.0" description = "Read metadata from Python packages" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy", "pytest-perf (>=0.9.2)"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "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 (>=0.9.2)"] [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -441,7 +495,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "loguru" -version = "0.5.3" +version = "0.6.0" description = "Python logging made (stupidly) simple" category = "main" optional = false @@ -452,7 +506,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -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)"] +dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "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)"] [[package]] name = "MarkupSafe" @@ -464,7 +518,7 @@ python-versions = ">=3.6" [[package]] name = "marshmallow" -version = "3.17.0" +version = "3.18.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." category = "main" optional = false @@ -474,9 +528,9 @@ python-versions = ">=3.7" packaging = ">=17.0" [package.extras] -dev = ["flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "mypy (==0.961)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.8)", "sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "mypy (==0.961)", "pre-commit (>=2.4,<3.0)"] +dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.1.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -521,11 +575,11 @@ python-versions = "*" [[package]] name = "outcome" -version = "1.1.0" +version = "1.2.0" description = "Capture the outcome of Python function calls." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" @@ -554,7 +608,7 @@ six = "*" [[package]] name = "pathspec" -version = "0.10.1" +version = "0.10.2" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false @@ -562,21 +616,21 @@ python-versions = ">=3.7" [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "2.5.4" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"] +test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -589,7 +643,7 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.21.7" +version = "4.21.9" description = "" category = "main" optional = false @@ -607,7 +661,7 @@ python-versions = ">=3.6" name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -629,14 +683,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pydantic" -version = "1.8.2" -description = "Data validation and settings management using python 3.6 type hinting" +version = "1.10.2" +description = "Data validation and settings management using python type hints" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] -typing-extensions = ">=3.7.4.3" +typing-extensions = ">=4.1.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] @@ -732,7 +786,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" name = "pytest" version = "7.1.3" description = "pytest: simple powerful testing with Python" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -753,7 +807,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "pytest-asyncio" version = "0.19.0" description = "Pytest support for asyncio" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -779,13 +833,21 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "python-bitcoinlib" +version = "0.11.2" +description = "The Swiss Army Knife of the Bitcoin protocol." +category = "main" +optional = false +python-versions = "*" + [[package]] name = "python-dotenv" -version = "0.19.0" +version = "0.21.0" description = "Read key-value pairs from a .env file and set them as environment variables" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [package.extras] cli = ["click (>=5.0)"] @@ -812,6 +874,24 @@ six = ">=1.8.0" [package.extras] test = ["ipython", "mock", "pytest (>=3.0.5)"] +[[package]] +name = "requests" +version = "2.27.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + [[package]] name = "rfc3986" version = "1.5.0" @@ -839,7 +919,7 @@ cffi = ">=1.3.0" [[package]] name = "setuptools" -version = "65.4.1" +version = "65.6.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false @@ -847,7 +927,7 @@ 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 (>=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 = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "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-timeout", "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]] @@ -868,15 +948,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sniffio" -version = "1.2.0" +version = "1.3.0" description = "Sniff out which async library your code is running under" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] name = "SQLAlchemy" -version = "1.3.23" +version = "1.3.24" description = "Database Abstraction Library" category = "main" optional = false @@ -939,7 +1019,7 @@ full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -953,7 +1033,7 @@ python-versions = ">=3.6" [[package]] name = "types-protobuf" -version = "3.20.4" +version = "3.20.4.6" description = "Typing stubs for protobuf" category = "dev" optional = false @@ -961,15 +1041,28 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.18.1" +version = "0.18.3" description = "The lightning-fast ASGI server." category = "main" optional = false @@ -981,7 +1074,7 @@ h11 = ">=0.8" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] +standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] [[package]] name = "uvloop" @@ -1038,20 +1131,20 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [[package]] name = "zipp" -version = "3.5.0" +version = "3.9.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7" -content-hash = "c4a01d5bfc24a8008348b6bd954717354554310afaaecbfc2a14222ad25aca42" +content-hash = "d8d786accf4ece1207e2f54ac37aba6601d089f9c1ca1269bf235d67b8e3e2a7" [metadata.files] aiofiles = [ @@ -1059,8 +1152,8 @@ aiofiles = [ {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, ] anyio = [ - {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"}, - {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, + {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, + {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, ] asgiref = [ {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, @@ -1075,8 +1168,8 @@ async-timeout = [ {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"}, + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, ] base58 = [ {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, @@ -1092,96 +1185,112 @@ bitstring = [ {file = "bitstring-3.1.9.tar.gz", hash = "sha256:a5848a3f63111785224dca8bb4c0a75b62ecdef56a042c8d6be74b16f7e860e7"}, ] black = [ - {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, - {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, - {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, - {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, - {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, - {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, - {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, - {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, - {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, - {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, - {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, - {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, - {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, - {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, - {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, - {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, - {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, - {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, - {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, + {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, + {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, + {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, + {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, + {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, + {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, + {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, + {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, + {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, + {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, + {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, + {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, + {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, + {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, + {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, + {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, + {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, + {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, + {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, + {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, + {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, +] +cashu = [ + {file = "cashu-0.5.4-py3-none-any.whl", hash = "sha256:de02245387fe0affaa1a02255ab9592c4115fd1deae57ccae3eee4610ab40ebb"}, + {file = "cashu-0.5.4.tar.gz", hash = "sha256:9fbfe21828282697bcc8ab7690c23509b867c9851beb525efd04ed386b84db10"}, ] Cerberus = [ {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"}, ] certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, ] cffi = [ - {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, - {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, - {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, - {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, - {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, - {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, - {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, - {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, - {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, - {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, - {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, - {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, - {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, - {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, - {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, - {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, - {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, - {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, + {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, + {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, ] coincurve = [ {file = "coincurve-17.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac8c87d6fd080faa74e7ecf64a6ed20c11a254863238759eb02c3f13ad12b0c4"}, @@ -1298,8 +1407,8 @@ cryptography = [ {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"}, ] ecdsa = [ - {file = "ecdsa-0.17.0-py2.py3-none-any.whl", hash = "sha256:5cf31d5b33743abe0dfc28999036c849a69d548f994b535e527ee3cb7f3ef676"}, - {file = "ecdsa-0.17.0.tar.gz", hash = "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa"}, + {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, + {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, ] embit = [ {file = "embit-0.4.9.tar.gz", hash = "sha256:992332bd89af6e2d027e26fe437eb14aa33997db08c882c49064d49c3e6f4ab9"}, @@ -1310,59 +1419,59 @@ enum34 = [ {file = "enum34-1.1.10.tar.gz", hash = "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248"}, ] environs = [ - {file = "environs-9.3.3-py2.py3-none-any.whl", hash = "sha256:ee5466156b50fe03aa9fec6e720feea577b5bf515d7f21b2c46608272557ba26"}, - {file = "environs-9.3.3.tar.gz", hash = "sha256:72b867ff7b553076cdd90f3ee01ecc1cf854987639c9c459f0ed0d3d44ae490c"}, + {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, + {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, ] fastapi = [ - {file = "fastapi-0.78.0-py3-none-any.whl", hash = "sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65"}, - {file = "fastapi-0.78.0.tar.gz", hash = "sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83"}, + {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, + {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, ] grpcio = [ - {file = "grpcio-1.49.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20"}, - {file = "grpcio-1.49.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f"}, - {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc"}, - {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b"}, - {file = "grpcio-1.49.1-cp310-cp310-win32.whl", hash = "sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788"}, - {file = "grpcio-1.49.1-cp310-cp310-win_amd64.whl", hash = "sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62"}, - {file = "grpcio-1.49.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b"}, - {file = "grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f"}, - {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201"}, - {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f"}, - {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568"}, - {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811"}, - {file = "grpcio-1.49.1-cp311-cp311-win32.whl", hash = "sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede"}, - {file = "grpcio-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2"}, - {file = "grpcio-1.49.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af"}, - {file = "grpcio-1.49.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e"}, - {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62"}, - {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3"}, - {file = "grpcio-1.49.1-cp37-cp37m-win32.whl", hash = "sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492"}, - {file = "grpcio-1.49.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf"}, - {file = "grpcio-1.49.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534"}, - {file = "grpcio-1.49.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df"}, - {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f"}, - {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3"}, - {file = "grpcio-1.49.1-cp38-cp38-win32.whl", hash = "sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2"}, - {file = "grpcio-1.49.1-cp38-cp38-win_amd64.whl", hash = "sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c"}, - {file = "grpcio-1.49.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde"}, - {file = "grpcio-1.49.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad"}, - {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f"}, - {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8"}, - {file = "grpcio-1.49.1-cp39-cp39-win32.whl", hash = "sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394"}, - {file = "grpcio-1.49.1-cp39-cp39-win_amd64.whl", hash = "sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705"}, - {file = "grpcio-1.49.1.tar.gz", hash = "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f"}, + {file = "grpcio-1.50.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:906f4d1beb83b3496be91684c47a5d870ee628715227d5d7c54b04a8de802974"}, + {file = "grpcio-1.50.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:2d9fd6e38b16c4d286a01e1776fdf6c7a4123d99ae8d6b3f0b4a03a34bf6ce45"}, + {file = "grpcio-1.50.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:4b123fbb7a777a2fedec684ca0b723d85e1d2379b6032a9a9b7851829ed3ca9a"}, + {file = "grpcio-1.50.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2f77a90ba7b85bfb31329f8eab9d9540da2cf8a302128fb1241d7ea239a5469"}, + {file = "grpcio-1.50.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eea18a878cffc804506d39c6682d71f6b42ec1c151d21865a95fae743fda500"}, + {file = "grpcio-1.50.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b71916fa8f9eb2abd93151fafe12e18cebb302686b924bd4ec39266211da525"}, + {file = "grpcio-1.50.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:95ce51f7a09491fb3da8cf3935005bff19983b77c4e9437ef77235d787b06842"}, + {file = "grpcio-1.50.0-cp310-cp310-win32.whl", hash = "sha256:f7025930039a011ed7d7e7ef95a1cb5f516e23c5a6ecc7947259b67bea8e06ca"}, + {file = "grpcio-1.50.0-cp310-cp310-win_amd64.whl", hash = "sha256:05f7c248e440f538aaad13eee78ef35f0541e73498dd6f832fe284542ac4b298"}, + {file = "grpcio-1.50.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:ca8a2254ab88482936ce941485c1c20cdeaef0efa71a61dbad171ab6758ec998"}, + {file = "grpcio-1.50.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3b611b3de3dfd2c47549ca01abfa9bbb95937eb0ea546ea1d762a335739887be"}, + {file = "grpcio-1.50.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a4cd8cb09d1bc70b3ea37802be484c5ae5a576108bad14728f2516279165dd7"}, + {file = "grpcio-1.50.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:156f8009e36780fab48c979c5605eda646065d4695deea4cfcbcfdd06627ddb6"}, + {file = "grpcio-1.50.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de411d2b030134b642c092e986d21aefb9d26a28bf5a18c47dd08ded411a3bc5"}, + {file = "grpcio-1.50.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d144ad10eeca4c1d1ce930faa105899f86f5d99cecfe0d7224f3c4c76265c15e"}, + {file = "grpcio-1.50.0-cp311-cp311-win32.whl", hash = "sha256:92d7635d1059d40d2ec29c8bf5ec58900120b3ce5150ef7414119430a4b2dd5c"}, + {file = "grpcio-1.50.0-cp311-cp311-win_amd64.whl", hash = "sha256:ce8513aee0af9c159319692bfbf488b718d1793d764798c3d5cff827a09e25ef"}, + {file = "grpcio-1.50.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:8e8999a097ad89b30d584c034929f7c0be280cd7851ac23e9067111167dcbf55"}, + {file = "grpcio-1.50.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:a50a1be449b9e238b9bd43d3857d40edf65df9416dea988929891d92a9f8a778"}, + {file = "grpcio-1.50.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:cf151f97f5f381163912e8952eb5b3afe89dec9ed723d1561d59cabf1e219a35"}, + {file = "grpcio-1.50.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a23d47f2fc7111869f0ff547f771733661ff2818562b04b9ed674fa208e261f4"}, + {file = "grpcio-1.50.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84d04dec64cc4ed726d07c5d17b73c343c8ddcd6b59c7199c801d6bbb9d9ed1"}, + {file = "grpcio-1.50.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:67dd41a31f6fc5c7db097a5c14a3fa588af54736ffc174af4411d34c4f306f68"}, + {file = "grpcio-1.50.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8d4c8e73bf20fb53fe5a7318e768b9734cf122fe671fcce75654b98ba12dfb75"}, + {file = "grpcio-1.50.0-cp37-cp37m-win32.whl", hash = "sha256:7489dbb901f4fdf7aec8d3753eadd40839c9085967737606d2c35b43074eea24"}, + {file = "grpcio-1.50.0-cp37-cp37m-win_amd64.whl", hash = "sha256:531f8b46f3d3db91d9ef285191825d108090856b3bc86a75b7c3930f16ce432f"}, + {file = "grpcio-1.50.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:d534d169673dd5e6e12fb57cc67664c2641361e1a0885545495e65a7b761b0f4"}, + {file = "grpcio-1.50.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:1d8d02dbb616c0a9260ce587eb751c9c7dc689bc39efa6a88cc4fa3e9c138a7b"}, + {file = "grpcio-1.50.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:baab51dcc4f2aecabf4ed1e2f57bceab240987c8b03533f1cef90890e6502067"}, + {file = "grpcio-1.50.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40838061e24f960b853d7bce85086c8e1b81c6342b1f4c47ff0edd44bbae2722"}, + {file = "grpcio-1.50.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:931e746d0f75b2a5cff0a1197d21827a3a2f400c06bace036762110f19d3d507"}, + {file = "grpcio-1.50.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:15f9e6d7f564e8f0776770e6ef32dac172c6f9960c478616c366862933fa08b4"}, + {file = "grpcio-1.50.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a4c23e54f58e016761b576976da6a34d876420b993f45f66a2bfb00363ecc1f9"}, + {file = "grpcio-1.50.0-cp38-cp38-win32.whl", hash = "sha256:3e4244c09cc1b65c286d709658c061f12c61c814be0b7030a2d9966ff02611e0"}, + {file = "grpcio-1.50.0-cp38-cp38-win_amd64.whl", hash = "sha256:8e69aa4e9b7f065f01d3fdcecbe0397895a772d99954bb82eefbb1682d274518"}, + {file = "grpcio-1.50.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:af98d49e56605a2912cf330b4627e5286243242706c3a9fa0bcec6e6f68646fc"}, + {file = "grpcio-1.50.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:080b66253f29e1646ac53ef288c12944b131a2829488ac3bac8f52abb4413c0d"}, + {file = "grpcio-1.50.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:ab5d0e3590f0a16cb88de4a3fa78d10eb66a84ca80901eb2c17c1d2c308c230f"}, + {file = "grpcio-1.50.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb11464f480e6103c59d558a3875bd84eed6723f0921290325ebe97262ae1347"}, + {file = "grpcio-1.50.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e07fe0d7ae395897981d16be61f0db9791f482f03fee7d1851fe20ddb4f69c03"}, + {file = "grpcio-1.50.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d75061367a69808ab2e84c960e9dce54749bcc1e44ad3f85deee3a6c75b4ede9"}, + {file = "grpcio-1.50.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ae23daa7eda93c1c49a9ecc316e027ceb99adbad750fbd3a56fa9e4a2ffd5ae0"}, + {file = "grpcio-1.50.0-cp39-cp39-win32.whl", hash = "sha256:177afaa7dba3ab5bfc211a71b90da1b887d441df33732e94e26860b3321434d9"}, + {file = "grpcio-1.50.0-cp39-cp39-win_amd64.whl", hash = "sha256:ea8ccf95e4c7e20419b7827aa5b6da6f02720270686ac63bd3493a651830235c"}, + {file = "grpcio-1.50.0.tar.gz", hash = "sha256:12b479839a5e753580b5e6053571de14006157f2ef9b71f38c56dc9b23b95ad6"}, ] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, @@ -1413,12 +1522,12 @@ httpx = [ {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, - {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, + {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, + {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1437,8 +1546,8 @@ lnurl = [ {file = "lnurl-0.3.6.tar.gz", hash = "sha256:8af07460115a48f3122a5a9c9a6062bee3897d5f6ab4c9a60f6561a83a8234f6"}, ] loguru = [ - {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, - {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, + {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, + {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, ] MarkupSafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, @@ -1512,8 +1621,8 @@ MarkupSafe = [ {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] marshmallow = [ - {file = "marshmallow-3.17.0-py3-none-any.whl", hash = "sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb"}, - {file = "marshmallow-3.17.0.tar.gz", hash = "sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"}, + {file = "marshmallow-3.18.0-py3-none-any.whl", hash = "sha256:35e02a3a06899c9119b785c12a22f4cda361745d66a71ab691fd7610202ae104"}, + {file = "marshmallow-3.18.0.tar.gz", hash = "sha256:6804c16114f7fce1f5b4dadc31f4674af23317fcc7f075da21e35c1a35d781f7"}, ] mock = [ {file = "mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62"}, @@ -1549,8 +1658,8 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] outcome = [ - {file = "outcome-1.1.0-py2.py3-none-any.whl", hash = "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958"}, - {file = "outcome-1.1.0.tar.gz", hash = "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967"}, + {file = "outcome-1.2.0-py2.py3-none-any.whl", hash = "sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5"}, + {file = "outcome-1.2.0.tar.gz", hash = "sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, @@ -1561,32 +1670,32 @@ pathlib2 = [ {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, ] pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, + {file = "pathspec-0.10.2-py3-none-any.whl", hash = "sha256:88c2606f2c1e818b978540f73ecc908e13999c6c3a383daf3705652ae79807a5"}, + {file = "pathspec-0.10.2.tar.gz", hash = "sha256:8f6bf73e5758fd365ef5d58ce09ac7c27d2833a8d7da51712eac6e27e35141b0"}, ] platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, + {file = "platformdirs-2.5.4-py3-none-any.whl", hash = "sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10"}, + {file = "platformdirs-2.5.4.tar.gz", hash = "sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] protobuf = [ - {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"}, + {file = "protobuf-4.21.9-cp310-abi3-win32.whl", hash = "sha256:6e0be9f09bf9b6cf497b27425487706fa48c6d1632ddd94dab1a5fe11a422392"}, + {file = "protobuf-4.21.9-cp310-abi3-win_amd64.whl", hash = "sha256:a7d0ea43949d45b836234f4ebb5ba0b22e7432d065394b532cdca8f98415e3cf"}, + {file = "protobuf-4.21.9-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b5ab0b8918c136345ff045d4b3d5f719b505b7c8af45092d7f45e304f55e50a1"}, + {file = "protobuf-4.21.9-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:2c9c2ed7466ad565f18668aa4731c535511c5d9a40c6da39524bccf43e441719"}, + {file = "protobuf-4.21.9-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:e575c57dc8b5b2b2caa436c16d44ef6981f2235eb7179bfc847557886376d740"}, + {file = "protobuf-4.21.9-cp37-cp37m-win32.whl", hash = "sha256:9227c14010acd9ae7702d6467b4625b6fe853175a6b150e539b21d2b2f2b409c"}, + {file = "protobuf-4.21.9-cp37-cp37m-win_amd64.whl", hash = "sha256:a419cc95fca8694804709b8c4f2326266d29659b126a93befe210f5bbc772536"}, + {file = "protobuf-4.21.9-cp38-cp38-win32.whl", hash = "sha256:5b0834e61fb38f34ba8840d7dcb2e5a2f03de0c714e0293b3963b79db26de8ce"}, + {file = "protobuf-4.21.9-cp38-cp38-win_amd64.whl", hash = "sha256:84ea107016244dfc1eecae7684f7ce13c788b9a644cd3fca5b77871366556444"}, + {file = "protobuf-4.21.9-cp39-cp39-win32.whl", hash = "sha256:f9eae277dd240ae19bb06ff4e2346e771252b0e619421965504bd1b1bba7c5fa"}, + {file = "protobuf-4.21.9-cp39-cp39-win_amd64.whl", hash = "sha256:6e312e280fbe3c74ea9e080d9e6080b636798b5e3939242298b591064470b06b"}, + {file = "protobuf-4.21.9-py2.py3-none-any.whl", hash = "sha256:7eb8f2cc41a34e9c956c256e3ac766cf4e1a4c9c925dc757a41a01be3e852965"}, + {file = "protobuf-4.21.9-py3-none-any.whl", hash = "sha256:48e2cd6b88c6ed3d5877a3ea40df79d08374088e89bedc32557348848dff250b"}, + {file = "protobuf-4.21.9.tar.gz", hash = "sha256:61f21493d96d2a77f9ca84fefa105872550ab5ef71d21c458eb80edcf4885a99"}, ] psycopg2-binary = [ {file = "psycopg2-binary-2.9.1.tar.gz", hash = "sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773"}, @@ -1664,28 +1773,42 @@ pycryptodomex = [ {file = "pycryptodomex-3.14.1.tar.gz", hash = "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2"}, ] pydantic = [ - {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, - {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, - {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, - {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, - {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, - {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, - {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, - {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, - {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, - {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, ] pyln-bolt7 = [ {file = "pyln-bolt7-1.0.246.tar.gz", hash = "sha256:2b53744fa21c1b12d2c9c9df153651b122e38fa65d4a5c3f2957317ee148e089"}, @@ -1730,9 +1853,13 @@ pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] +python-bitcoinlib = [ + {file = "python-bitcoinlib-0.11.2.tar.gz", hash = "sha256:61ba514e0d232cc84741e49862dcedaf37199b40bba252a17edc654f63d13f39"}, + {file = "python_bitcoinlib-0.11.2-py3-none-any.whl", hash = "sha256:78bd4ee717fe805cd760dfdd08765e77b7c7dbef4627f8596285e84953756508"}, +] 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"}, + {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, + {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, ] PyYAML = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, @@ -1769,6 +1896,10 @@ 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"}, ] +requests = [ + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, +] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, @@ -1799,8 +1930,8 @@ secp256k1 = [ {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, ] setuptools = [ - {file = "setuptools-65.4.1-py3-none-any.whl", hash = "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012"}, - {file = "setuptools-65.4.1.tar.gz", hash = "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e"}, + {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, + {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, ] shortuuid = [ {file = "shortuuid-1.0.1-py3-none-any.whl", hash = "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77"}, @@ -1811,48 +1942,44 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] 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"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-win32.whl", hash = "sha256:b4b0e44d586cd64b65b507fa116a3814a1a53d55dce4836d7c1a6eb2823ff8d1"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-win_amd64.whl", hash = "sha256:6b8b8c80c7f384f06825612dd078e4a31f0185e8f1f6b8c19e188ff246334205"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9e9c25522933e569e8b53ccc644dc993cab87e922fb7e142894653880fdd419d"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a0e306e9bb76fd93b29ae3a5155298e4c1b504c7cbc620c09c20858d32d16234"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:6c9e6cc9237de5660bcddea63f332428bb83c8e2015c26777281f7ffbd2efb84"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:94f667d86be82dd4cb17d08de0c3622e77ca865320e0b95eae6153faa7b4ecaf"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:751934967f5336a3e26fc5993ccad1e4fee982029f9317eb6153bc0bc3d2d2da"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:63677d0c08524af4c5893c18dbe42141de7178001360b3de0b86217502ed3601"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-win32.whl", hash = "sha256:ddfb511e76d016c3a160910642d57f4587dc542ce5ee823b0d415134790eeeb9"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-win_amd64.whl", hash = "sha256:040bdfc1d76a9074717a3f43455685f781c581f94472b010cd6c4754754e1862"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d1a85dfc5dee741bf49cb9b6b6b8d2725a268e4992507cf151cba26b17d97c37"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:639940bbe1108ac667dcffc79925db2966826c270112e9159439ab6bb14f8d80"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8a1750b44ad6422ace82bf3466638f1aa0862dbb9689690d5f2f48cce3476c8"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e5bb3463df697279e5459a7316ad5a60b04b0107f9392e88674d0ece70e9cf70"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-win32.whl", hash = "sha256:e273367f4076bd7b9a8dc2e771978ef2bfd6b82526e80775a7db52bff8ca01dd"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-win_amd64.whl", hash = "sha256:ac2244e64485c3778f012951fdc869969a736cd61375fde6096d08850d8be729"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:23927c3981d1ec6b4ea71eb99d28424b874d9c696a21e5fbd9fa322718be3708"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d90010304abb4102123d10cbad2cdf2c25a9f2e66a50974199b24b468509bad5"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a8bfc1e1afe523e94974132d7230b82ca7fa2511aedde1f537ec54db0399541a"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:269990b3ab53cb035d662dcde51df0943c1417bdab707dc4a7e4114a710504b4"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-win32.whl", hash = "sha256:fdd2ed7395df8ac2dbb10cefc44737b66c6a5cd7755c92524733d7a443e5b7e2"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-win_amd64.whl", hash = "sha256:6a939a868fdaa4b504e8b9d4a61f21aac11e3fecc8a8214455e144939e3d2aea"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:24f9569e82a009a09ce2d263559acb3466eba2617203170e4a0af91e75b4f075"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2578dbdbe4dbb0e5126fb37ffcd9793a25dcad769a95f171a2161030bea850ff"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1fe5d8d39118c2b018c215c37b73fd6893c3e1d4895be745ca8ff6eb83333ed3"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c7dc052432cd5d060d7437e217dd33c97025287f99a69a50e2dc1478dd610d64"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-win32.whl", hash = "sha256:ecce8c021894a77d89808222b1ff9687ad84db54d18e4bd0500ca766737faaf6"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:37b83bf81b4b85dda273aaaed5f35ea20ad80606f672d94d2218afc565fb0173"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8be835aac18ec85351385e17b8665bd4d63083a7160a017bef3d640e8e65cadb"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6ec1044908414013ebfe363450c22f14698803ce97fbb47e53284d55c5165848"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eab063a70cca4a587c28824e18be41d8ecc4457f8f15b2933584c6c6cccd30f0"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:baeb451ee23e264de3f577fee5283c73d9bbaa8cb921d0305c0bbf700094b65b"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-win32.whl", hash = "sha256:94208867f34e60f54a33a37f1c117251be91a47e3bfdb9ab8a7847f20886ad06"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:f4d972139d5000105fcda9539a76452039434013570d6059993120dc2a65e447"}, - {file = "SQLAlchemy-1.3.23.tar.gz", hash = "sha256:6fca33672578666f657c131552c4ef8979c1606e494f78cd5199742dfb26918b"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, + {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, ] sqlalchemy-aio = [ {file = "sqlalchemy_aio-0.17.0-py3-none-any.whl", hash = "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60"}, @@ -1896,17 +2023,20 @@ typed-ast = [ {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] types-protobuf = [ - {file = "types-protobuf-3.20.4.tar.gz", hash = "sha256:0dad3a5009895c985a56e2837f61902bad9594151265ac0ee907bb16d0b01eb7"}, - {file = "types_protobuf-3.20.4-py3-none-any.whl", hash = "sha256:5082437afe64ce3b31c8db109eae86e02fda11e4d5f9ac59cb8578a8a138aa70"}, + {file = "types-protobuf-3.20.4.6.tar.gz", hash = "sha256:ba27443c592bbec1629dd69494a24c84461c63f0d3b7d648ce258aaae9680965"}, + {file = "types_protobuf-3.20.4.6-py3-none-any.whl", hash = "sha256:ab2d315ba82246b83d28f8797c98dc0fe1dd5cfd187909e56faf87239aedaae3"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] uvicorn = [ - {file = "uvicorn-0.18.1-py3-none-any.whl", hash = "sha256:013c4ea0787cc2dc456ef4368e18c01982e6be57903e4d3183218e543eb889b7"}, - {file = "uvicorn-0.18.1.tar.gz", hash = "sha256:35703e6518105cfe53f16a5a9435db3e2e227d0784f1fd8fbc1214b1fdc108df"}, + {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, + {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, ] uvloop = [ {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, @@ -1966,6 +2096,6 @@ win32-setctime = [ {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, ] zipp = [ - {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, - {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, + {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, + {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, ] diff --git a/pyproject.toml b/pyproject.toml index e66073c5d..5bd685b12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,58 +12,60 @@ script = "build.py" python = "^3.10 | ^3.9 | ^3.8 | ^3.7" aiofiles = "0.8.0" asgiref = "3.4.1" -attrs = "21.2.0" +attrs = "22.1.0" bech32 = "1.2.0" bitstring = "3.1.9" -certifi = "2021.5.30" -charset-normalizer = "2.0.6" -click = "8.0.1" -ecdsa = "0.17.0" +certifi = "2022.9.24" +charset-normalizer = "2.0.12" +click = "8.0.4" +ecdsa = "0.18.0" embit = "0.4.9" -environs = "9.3.3" -fastapi = "0.78.0" +environs = "9.5.0" +fastapi = "0.83.0" h11 = "0.12.0" httpcore = "0.15.0" httptools = "0.4.0" httpx = "0.23.0" -idna = "3.2" -importlib-metadata = "4.8.1" +idna = "3.4" +importlib-metadata = "5.0.0" jinja2 = "3.0.1" lnurl = "0.3.6" markupsafe = "2.0.1" -marshmallow = "3.17.0" -outcome = "1.1.0" +marshmallow = "3.18.0" +outcome = "1.2.0" psycopg2-binary = "2.9.1" pycryptodomex = "3.14.1" -pydantic = "1.8.2" +pydantic = "1.10.2" pypng = "0.0.21" pyqrcode = "1.2.1" pyScss = "1.4.0" -python-dotenv = "0.19.0" +python-dotenv = "0.21.0" pyyaml = "5.4.1" represent = "1.6.0.post0" rfc3986 = "1.5.0" secp256k1 = "0.14.0" shortuuid = "1.0.1" six = "1.16.0" -sniffio = "1.2.0" -sqlalchemy = "1.3.23" +sniffio = "1.3.0" +sqlalchemy = "1.3.24" sqlalchemy-aio = "0.17.0" sse-starlette = "0.6.2" -typing-extensions = "3.10.0.2" -uvicorn = "0.18.1" +typing-extensions = "^4.4.0" +uvicorn = "0.18.3" uvloop = "0.16.0" watchgod = "0.7" websockets = "10.0" -zipp = "3.5.0" -loguru = "0.5.3" -cffi = "1.15.0" +zipp = "3.9.0" +loguru = "0.6.0" +cffi = "1.15.1" 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" +cashu = "0.5.4" + [tool.poetry.dev-dependencies] isort = "^5.10.1" diff --git a/requirements.txt b/requirements.txt index 1431478ca..06e8642f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,45 +1,49 @@ aiofiles==0.8.0 ; python_version >= "3.7" and python_version < "4.0" -anyio==3.6.1 ; python_version >= "3.7" and python_version < "4.0" +anyio==3.6.2 ; python_version >= "3.7" and python_version < "4.0" asgiref==3.4.1 ; python_version >= "3.7" and python_version < "4.0" asn1crypto==1.5.1 ; python_version >= "3.7" and python_version < "4.0" async-timeout==4.0.2 ; python_version >= "3.7" and python_version < "4.0" -attrs==21.2.0 ; python_version >= "3.7" and python_version < "4.0" +attrs==22.1.0 ; python_version >= "3.7" and python_version < "4.0" base58==2.1.1 ; python_version >= "3.7" and python_version < "4.0" bech32==1.2.0 ; python_version >= "3.7" and python_version < "4.0" bitstring==3.1.9 ; python_version >= "3.7" and python_version < "4.0" +cashu==0.5.4 ; python_version >= "3.7" and python_version < "4.0" cerberus==1.3.4 ; python_version >= "3.7" and python_version < "4.0" -certifi==2021.5.30 ; python_version >= "3.7" and python_version < "4.0" -cffi==1.15.0 ; python_version >= "3.7" and python_version < "4.0" -charset-normalizer==2.0.6 ; python_version >= "3.7" and python_version < "4.0" -click==8.0.1 ; python_version >= "3.7" and python_version < "4.0" +certifi==2022.9.24 ; python_version >= "3.7" and python_version < "4.0" +cffi==1.15.1 ; python_version >= "3.7" and python_version < "4.0" +charset-normalizer==2.0.12 ; python_version >= "3.7" and python_version < "4.0" +click==8.0.4 ; python_version >= "3.7" and python_version < "4.0" coincurve==17.0.0 ; python_version >= "3.7" and python_version < "4.0" colorama==0.4.5 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" cryptography==36.0.2 ; python_version >= "3.7" and python_version < "4.0" -ecdsa==0.17.0 ; python_version >= "3.7" and python_version < "4.0" +ecdsa==0.18.0 ; python_version >= "3.7" and python_version < "4.0" embit==0.4.9 ; python_version >= "3.7" and python_version < "4.0" enum34==1.1.10 ; python_version >= "3.7" and python_version < "4.0" -environs==9.3.3 ; python_version >= "3.7" and python_version < "4.0" -fastapi==0.78.0 ; python_version >= "3.7" and python_version < "4.0" -grpcio==1.49.1 ; python_version >= "3.7" and python_version < "4.0" +environs==9.5.0 ; python_version >= "3.7" and python_version < "4.0" +fastapi==0.83.0 ; python_version >= "3.7" and python_version < "4.0" +grpcio==1.50.0 ; python_version >= "3.7" and python_version < "4.0" h11==0.12.0 ; python_version >= "3.7" and python_version < "4.0" httpcore==0.15.0 ; python_version >= "3.7" and python_version < "4.0" httptools==0.4.0 ; python_version >= "3.7" and python_version < "4.0" httpx==0.23.0 ; python_version >= "3.7" and python_version < "4.0" -idna==3.2 ; python_version >= "3.7" and python_version < "4.0" -importlib-metadata==4.8.1 ; python_version >= "3.7" and python_version < "4.0" +idna==3.4 ; python_version >= "3.7" and python_version < "4.0" +importlib-metadata==5.0.0 ; python_version >= "3.7" and python_version < "4.0" +iniconfig==1.1.1 ; python_version >= "3.7" and python_version < "4.0" jinja2==3.0.1 ; python_version >= "3.7" and python_version < "4.0" lnurl==0.3.6 ; python_version >= "3.7" and python_version < "4.0" -loguru==0.5.3 ; python_version >= "3.7" and python_version < "4.0" +loguru==0.6.0 ; python_version >= "3.7" and python_version < "4.0" markupsafe==2.0.1 ; python_version >= "3.7" and python_version < "4.0" -marshmallow==3.17.0 ; python_version >= "3.7" and python_version < "4.0" -outcome==1.1.0 ; python_version >= "3.7" and python_version < "4.0" +marshmallow==3.18.0 ; python_version >= "3.7" and python_version < "4.0" +outcome==1.2.0 ; python_version >= "3.7" and python_version < "4.0" packaging==21.3 ; python_version >= "3.7" and python_version < "4.0" pathlib2==2.3.7.post1 ; python_version >= "3.7" and python_version < "4.0" -protobuf==4.21.7 ; python_version >= "3.7" and python_version < "4.0" +pluggy==1.0.0 ; python_version >= "3.7" and python_version < "4.0" +protobuf==4.21.9 ; python_version >= "3.7" and python_version < "4.0" psycopg2-binary==2.9.1 ; python_version >= "3.7" and python_version < "4.0" +py==1.11.0 ; python_version >= "3.7" and python_version < "4.0" pycparser==2.21 ; python_version >= "3.7" and python_version < "4.0" pycryptodomex==3.14.1 ; python_version >= "3.7" and python_version < "4.0" -pydantic==1.8.2 ; python_version >= "3.7" and python_version < "4.0" +pydantic==1.10.2 ; python_version >= "3.7" and python_version < "4.0" pyln-bolt7==1.0.246 ; python_version >= "3.7" and python_version < "4.0" pyln-client==0.11.1 ; python_version >= "3.7" and python_version < "4.0" pyln-proto==0.11.1 ; python_version >= "3.7" and python_version < "4.0" @@ -48,25 +52,31 @@ pypng==0.0.21 ; python_version >= "3.7" and python_version < "4.0" pyqrcode==1.2.1 ; python_version >= "3.7" and python_version < "4.0" pyscss==1.4.0 ; python_version >= "3.7" and python_version < "4.0" pysocks==1.7.1 ; python_version >= "3.7" and python_version < "4.0" -python-dotenv==0.19.0 ; python_version >= "3.7" and python_version < "4.0" +pytest-asyncio==0.19.0 ; python_version >= "3.7" and python_version < "4.0" +pytest==7.1.3 ; python_version >= "3.7" and python_version < "4.0" +python-bitcoinlib==0.11.2 ; python_version >= "3.7" and python_version < "4.0" +python-dotenv==0.21.0 ; python_version >= "3.7" and python_version < "4.0" pyyaml==5.4.1 ; python_version >= "3.7" and python_version < "4.0" represent==1.6.0.post0 ; python_version >= "3.7" and python_version < "4.0" +requests==2.27.1 ; python_version >= "3.7" and python_version < "4.0" rfc3986==1.5.0 ; python_version >= "3.7" and python_version < "4.0" rfc3986[idna2008]==1.5.0 ; python_version >= "3.7" and python_version < "4.0" secp256k1==0.14.0 ; python_version >= "3.7" and python_version < "4.0" -setuptools==65.4.1 ; python_version >= "3.7" and python_version < "4.0" +setuptools==65.6.3 ; python_version >= "3.7" and python_version < "4.0" shortuuid==1.0.1 ; python_version >= "3.7" and python_version < "4.0" six==1.16.0 ; python_version >= "3.7" and python_version < "4.0" -sniffio==1.2.0 ; python_version >= "3.7" and python_version < "4.0" +sniffio==1.3.0 ; python_version >= "3.7" and python_version < "4.0" sqlalchemy-aio==0.17.0 ; python_version >= "3.7" and python_version < "4.0" -sqlalchemy==1.3.23 ; python_version >= "3.7" and python_version < "4.0" +sqlalchemy==1.3.24 ; python_version >= "3.7" and python_version < "4.0" sse-starlette==0.6.2 ; python_version >= "3.7" and python_version < "4.0" starlette==0.19.1 ; python_version >= "3.7" and python_version < "4.0" -typing-extensions==3.10.0.2 ; python_version >= "3.7" and python_version < "4.0" -uvicorn==0.18.1 ; python_version >= "3.7" and python_version < "4.0" +tomli==2.0.1 ; python_version >= "3.7" and python_version < "4.0" +typing-extensions==4.4.0 ; python_version >= "3.7" and python_version < "4.0" +urllib3==1.26.12 ; python_version >= "3.7" and python_version < "4" +uvicorn==0.18.3 ; python_version >= "3.7" and python_version < "4.0" uvloop==0.16.0 ; python_version >= "3.7" and python_version < "4.0" watchgod==0.7 ; python_version >= "3.7" and python_version < "4.0" websocket-client==1.3.3 ; python_version >= "3.7" and python_version < "4.0" websockets==10.0 ; python_version >= "3.7" and python_version < "4.0" win32-setctime==1.1.0 ; python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" -zipp==3.5.0 ; python_version >= "3.7" and python_version < "4.0" +zipp==3.9.0 ; python_version >= "3.7" and python_version < "4.0" diff --git a/tests/data/mock_data.zip b/tests/data/mock_data.zip index 5a52941c74a0ef02265cb3ad046998b113cfa3a0..e992b988747cae0cb4472f77ab7f21d70787fb1b 100644 GIT binary patch literal 37478 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 literal 30790 zcmb4r1yo#1)-^#xNRZ&}?h@P~xVsbFY1}2a1a~L6ySuvucMHMYo&F(tGxIWU=KbGX zR^L^9yQy1s&aP9tcAeWY;$YxNATI}=g0bSy!XKwMAb21a06jBpeH}X;T1AC-AW)o0 zrh5N)**n32yaK;`1p@N(|7CvG^BUy!Z}lua*M;<4kG8fXpMbQy3N4NHKdbz$Mu+E` z|E)&7Psn;kpL9Q+NJ=Q3z$pdFdWI!0-K4A|i~O_rNRH z7Xg1XJte&;UPUG%x-dRDAq5OcU*`ti)k)nTfaCa0hq87{-i`yJ5iL6ih>SSYYc8bn zFPhH{d}-vrnolbO{x36p1p&eN%?t)kcG|W&cDDK^dImJM*5)R528=&DGGw{0yZHRV z{%c1L7sde-yjbn04tnJo-7Oys;h6EondVcBLxQ-C^HTAP*3gJX6PU15GE~*ks`a=n z8J{rk(r=7zwtPJO!Wk+<<;2k7OefrUL`7X4m#o{GD4F_>!gTKWALsV!( z`bJr53x!dPn>OA2ex{W$NvY0cCOOmN8%!!qOYx4HqH@tfZbnhY+e=HOcNLhXik`}f zt4hIu>cO-C zWZpTtfu6uq3T~+0*i~|9*fgfNNRRLtgX@ecy*Nmjw+tFJlGBwA9)Fi2C97cfY zo;bc6H;Xm&FuNhwkhL!^qSWdYHbV5#LR!PBr?7d1=Dw3n?q)6M7%r|)KhgVC!f`sy zb#>*B;+utPh3G=&0}e)FY%Er8O^0)tS(fMq)D!8s29A4PxbcbrH7(8V%>#8!ohyLX zY@&Y``ISCRiFuipkykj)(e2Zt`{@HoI)|s~Q`suxvjagu)@U)!PtG6UUdp_g6~JGG zvws#&|M=+a6zKW#9gwK-$NyS5hI<(oPqvve#h}k${rcx|LHFlzAp-(}{g-iJYHwzs z3vl{vSPcKou$b>Ko0NGT7V)Kv+3Ky!15`b*&~IhT-}E6!XCv`X z1zRX;ko8^qRS=dcBVKo@AN8`xI{MYm&)s}~bG?s?1@&SL&*gyS*h|BvL$@XRaoNlj zslGijj(4Qv2P!$a48=T$&Z+Iud`64c`o!b_mLJ~EOjsXXh`^5R@w6|l(i~j^&JrD+ zuH{UeGwE zpkmwi@`OiSs-|tY9Z`?FAMyq(RqQ$~KJ>P|KoZ-bAzRZo8;ej`NOXaC?>7F&TJC`})Nw zAWs!S4I7WRFU8L}z1P3+5{J7Ae2(@YASxcKuU>GHx^48M<>ksV8vYeO{~afUf5C~Z z)pOXi(s8yhu(Y%NAJ8J+`GOV}P4vzQb>H|^*$)2Qq{#WN#$<8)slA2BopQF(?6cal zo>LVp$x-opx$Y7LYdoT|tqEFp}& z*hpZQnw6+Iv{c(ir7)<8nI3HE?qk_{>0CSDI!4rp`3=Oze0cK^FH4p>&ztDzdDfbJ zY<2cau)eq-xky!K9X_Z#CKDB7924fdJM2=no>d~e-a!H;ss29yvl}cY8eiR*T3F@!_igFy4V3ycj*j$kAI(&wH zS;Ck+UYT5by$gyio9=$HTQl2M*^J+!-!+-@nS&b#h6~PS>7cRVa5FGLT5$SCkgSJC z+241U>2-8IgOGKJ@v17zFsUep*+P}3+2I@AJ4t^6ZC_0~faKJypb5e_<7`dhW-;_$ z1J1rS>#ajgdfbPCK9^y=Q8vtP9nI1;2KsS`BbM%U18R_w)_A zZyGl(JW5>?^X?mK7Z2=0)~V*DMz7DldV%9_@dEQtv=bZ+1O)Ln zz|jcGYs=dKYz%&qES6_-^^e!TvBkp#4%kjQctN937;z>V@?|R!%TFH%pzA>(l)qk& z<1ZjoBFV`Rdpk#6Dg}F*U`d0_oz!c8ev8);%E%oxhvHkxJc{oN&mZWnS8BK9fXN?- z&5#b~S88XAnGVJ7pvR!OBgRr!q5YLGbw>iVabjddUSF>(>>?(k~`41qrmM ze749-$Nv>V|7;Sc=TBcK=sy|sKl$@Bm;S4DUU>BX#HA}R;eBq9d51yd*YVmvgR%Pi zg7YOJ(`oL!GzjW7Okg|fhvz1|G~-_lWc@Q2umS0~bxg7w!@!hX`E;Awr&Gt7}2GAm#aJ=REH~@&L?nPa2N}cPAGkIdJhaQYZ8L88T!@Z~XYz#YeN!Yq!QqisM! zCx9!iuGQr$ODkM+t4E<}V=XnUE(UrvRo0s$m_@1MMXAbC_WnD$qrH1@EbOb=ZLJOl zj}F^SMRl~;j812_V~3U=;bH15mRKx}P>YMKGrBM?>Kmok>!bBUjykvwE*n&9mX7CK zZspDwykoU{M-KOzb1R%XI%T$xTfKXWMf<5mMXL=q`@KQ|xOK~Y*m(EL9AmYHeI*;* z{J4{bZB0JHwSCmEN4d}_b(UJ5+cSHV_Qf>Z4OXX@4)+I5lp{ipEbEUe_lp;XHPBFx zEgiR8J2#fW<8imM+i68$+zS&P7l&I9^S0YbJf8dYAn9UdEa&FqTy;w%l)L(1?)uXL z7zv1%0ZrDlKmk^=9-(@uK8HjpXN%f z4^nZ(w@s}4!HJ9(jaHxe^+Q0;q}f0sqQ_2whD#NbD)kiOjND^i0Sm@-&89ZZqkX~o z#LVt$>RkxNvmbuB!^kQhRjRC{1dArM!D-7pHZ^?Sut;)Pj1_^Gd>gqN$(!#Y5ei+e zoF7d=ikS2RjGUPQKkI1dG(CDyFIs9w@5ASza+*)q>O&T+sBbq(3fNF)W%*!*_%zVp-V?)nU~ zf@grVyjw5>IJpzP0R_EgFzD*NUB)?657w`KJ51o$O^1#JY1A^nCr<0G6xhqrnBmAr zj|g_|MX<5AV`dq366s1RAr`lZgghD1qCC$KGAf=JTN_1BlUc{jHY^gp179;Zs`|2l3rqwkiB<%eUG(BuxJ2{xHD4g~BVD=nD;~9iFqTH>UCzq z&YM190dP&e)(;Xve5`;D^9k=|GyG;sQ~ZVg4zEF9OBL@?p3;_01OO@>DO#BGc%b6g~m@8~eO zWoAr*CW)w(KqpvnmH(M$PE11wZzukU;2@1C!&{w{RYn1i^9aN*9WZnn8PV&LNCik7-If^ZxE|IgXKpob$qpiwnr@nyz10OzD(^lERQ3XlmVO|$ z5TLUQmpGAk6#ys%I+o~>EZz$cAZ8=>}GeoUHQFrL`zANHHC=@I2X@VN%=Ib_{g zT$b&HPiO7XP9K`q-CY7*ZvHt4pU2{j*vaL5?3OXxB>yt28YPo9OBl-c>iynviui^` z>uTR@MV7D`qhSw^>x~{bMk7OI6k$r3y*uDlCoaZNI@RM|4sLpD^$mcX{3XUd*B5mr zQx`uwGXop1#igOHs$pECE0!QpuG(MREW(%ndBD0iOOSNBdUJQ`^`#@d9KBkpXnbaA zkv5{3x@UNnk63m6cm0nrRQ~-cOlc5#C3VpCO|yr99QXRVuw&d$Wx(ijj^$-sPRkf8A&)SAH!+ACp>#GcjEA89raJHI zm(Qf*n0eng8I8kfQ>b*a%4nrynO!*rBx~{Zm)1CE+n7%n)RW=y+_qv@s4G_V-Tjl&*sM2OWZ); zQwS3ik9w_2;K;o#VU!@>xS{rSk}FaOsMus0LolUF z!9^#rA3LNdBNb`lOQ&0pxq}urw@%+G4#>H=W*k-W+*t;vf4=as{fxCaA^-{-XD zwdEob5Qrom0R>HorpF^@4*f!`V>>mIK&I&s6eOrM8PhNCq=U}hh;D^cad!`Nu+NY^ zR7h9CRm4@E-O2tl{((GuYWJcXLq2yv(Z&3iv#bBlvi{F9|H~N@?-}o#xF6y?s~*Dl zuBZ9z6Q%wPbSE4o^#Jh^lP|doK3cid_(_--3>JKnX5WUYKay0vTxv*Y5Nn~5QvZCS z{X(eVMzN-UysWaHY16+5)xR&A@%}=nZ0&XRpZS!D<^Ql^9uwQ(#ezB!E%B5I?!*z3 zPW@8-Q57DyUD947*kpg^^**^oGC5?lgk-Kli_3}06&JX6XW!fgNkQ+`H+|Izzh{w! zB=JYGzKF+LUyTPkEaDv*NF3#hhy!>@!c{V2U!+WfShv9Yp2Sw6Gvt2dBDsYp$zb)d z?2E?7%1e#AOVsUG&m9Hf_3wKcbZJnVPHQDwas0@7v^cR5mTrj@?kd58{^2sW!?-bd zhGq9{UoOeL$;7!W%ZJ;bA0Zh>wDnga(pg9VXQ0?lV2Z!&~niZ`$Tie4@yV|rX76rX`MJLn1lDn*AgN3B_qj+h}q1hdYl^zN`FhQF3WioGpp1Zs9`O?kFq_M0`o{($erZ%(3dNPsNDWyc+V!jw>CO*4hdteS(L0Ck53)4oa zdEY{Ly?E(A%^d|e%qj_Lmx1ug6V5QCBo7Ez#zF08pjws;(3>1pIzOfZt3A`=v6IO}I@RFF5 zdbG<)<1*G2`$;i~==%AKou!p#3ufxTz$Xrz$FijkZC-hExL%RgbbUicj$`5>*Y%St z9_G%eel1R{9fei|%1-NU4st*E26HY%#{)JV2Z!!Qo9~ME1{qE?XMSl;vgBGwEWnWyg&k z;z#*2cY^IK%g4zV6#Zs~`(MWsLIN+^hZ}Jdh{n^6{E65l^_TA#?J;mX$Ggy9sY_~4 z*KyrnP8Y2uT};QF#nu&E9Ueb@4G{fsFk?AsT6EiUwird&nQzugO8RInVzEETgp;~h zt8nd-l|rdPigs*r z?)+G@$B$ffBkia8mSQqf_1leiF-Lsgid|KoO3%E3W;2h6VOd>-*g{zm1saoV!5d{+ z$xZC2=7&l+mt#NUIS3BgInPgYoQL1yz7#&+)|sRnt?5@o(zD#qF&(mBZl5{z0&V`|6HZ{)I1F&M*zMKS{VuYFG z(5ysV<0NZF`Msl@%7d<3eyt>?3bnb~&dUC{W2i*^PL`2%9&+E5G?g@zYQip@*$c#Z zJb%8c=Q&P4(;%`r@P1y|-Dfxsze!5R{xMQtSxx^?_faROM#;U4^`|9n;FdhqRYp<2 z^d5&NY2SG_S(3$wDbM>bGg=5)*skg_EsGAZ-34#UCA-&{6loSEAKJPMkJj~pf*sxS zlV%7ps*O^aajp;ITzi{9BS1Xpd~);D4x(G*qPH-&am%ChXvQZ7y%uumn3`17pj0!P zJAg5hZp`%PuOan8ufW7vZh17E)HT%O7j!+Hp58l{V%{&24aBJ=JRhz!QQa*^3>eIj zR9wi-;e{289o%7|;F!;8R%HrAt^cm%ew|e(9B^HOb(LD3EA?SnrMZbY?%dD&)Xa<( zH)?{&!qA*K`=e{X03Ce%tegXo4!e{+EKZZ&-Y({r9BiF4ea|;W!A0owsgXfFG3Q~s zGkcKex}$((-)~3u5uT^4$hzvZ)D!)uou1|A@Xha#$G|_{*}nT@Qvn2I3%B)`Kn(&i z+(!C>p;utc{^58>+~e{zfA<0B9?89!X0=@GGD?v)z6_WF z`O^q%TunDy)WtKVD~hv0S_JoCk&jUhclqXy^|&@~9!ow?UJ!nW+kr-w?++JPSR4~( zdA;*>()2zRabc4blQGdukFu(!>0q8Wg=Ki^8+n#^rqFh1Y+4{uU^Nch)UC$iZl`bHSU{TDB!N6PXsrxp~0R2TW-$uJnI_(m-DIjKFQyH-XwB9zijai za=IpQDtROzG$}b2uE=9VPpt23I4tTx2{)*M(Q)6{#W<68GXA?(n+jI5DSgSqY}L>G z%4a(O%nK5%fIp+{v)VXo`E!fH^n55Q?gaqPZvGcp{tW;!&xs4qfB#ZNU(`o)69)s^ zpW76_Vc_o=&8)Wcqzqc$X`BU(EW&YI4~*2@JD6@`H!vmEh#t9eJLo1;Q&$m;CfGaS z(vQyAt?yTpHBrSlpf#MbhOVQ{cjwu*P40*0du;Cp-ZB!88VyVhb#ol%lr)-6NazGYlq_sLHdLPEAp42MBuiY?N zZ5;gMROs&fDMV7Z*~BuarJ%8Hf~wy=R>9ts)}EuzDQ6FM`f2^LNU5%_p#ZoOGp@8> z^u>X2O|8Wff1`v`aX=|i)V^&in39$Pc36P2P~li~TmMiLU?iL#GoKwVJ3i1@&^WAk zKntfHni5A+x6Lw7Ez||5SUG$Ld3VjHT7@EVXj39vgs`9udF6z)E!Keg1Qu|1I8ktM zP9$r+6$fltv~WZibv@7A{RI)qkf&cW&$RF#{A4fd7kWNjK0>|(k2%>deWQOLJf5+G z|5xl-+S{1x8#w$g2_Ey3W{Y%a?bd9P+GHaO>T{Cu5#WP(=H>g%qkb}ZhwtM{=w54O z$}sj>QX6QNxi(y59ugilZX6)Z5anv2WBMEb!C=H)^wnLy@zq~XybFoSVnx3f;zr@< ztn6ldW+^!rYRGk!F3!1@LE4l-!jA#5hsT-C_S86>^G}WTnzs(&)-Mox0>fP`E>>2j z-al`@0SF)qMH68aUU%@O-Ye@NC%TC{m+jA`5pvx(?DxC1nVS!ycgVPmnn~l}HXW26Ka=V9m3uA8YK2&?TRe)?@OYP zIe>OUKli9Ux0y3ivi_P`%BODrK+D+%kmto@AVbGcFKDSB%C&3zd$c^qAdJ7D#m)-w zJ5%}F7&9W)#S0I0GOwWU=CK|EU|TJNbV`Lr3`Ot3BvhUUzlaQG@;;h+Pu7iFJ5zdn z{J^xPA^$Z&KM;yzK6Thq#3rfA3zc#}S(QEr2_PTu`&HABz_dA(jZ0fi1?Eo8hq<#x zX*;p_DrBK*bdu%jXaAn}J=?o#R4OdgIV}r!7$Pag1}DJHRvlB@H{0jWHJHh@0B7D# z!(OfkCk38XKW+rL?E)UvIxJ!oNLx{`(-k(B&i9Z_m?G1caV5X-=VslzjJS%XE2ae0 z^z9HzFb^rFr9a{Q z(V`mzN$hX`nClQL#TEDz>JGl3* zE2;WCM<>aV;^1fOGW)Ty9D1l!XXZ{qNXkuYCly4JF)50Nh#ZwRNKezU{vdOpuVXxJ^xwo@5=g7_-wIhWnDa@Xs_M~~n)DPO>k&qa%0 zGL*>>IPvY|sl)yivMHeeArtzBJa5iAmFdL9h9tpiGb+!0J*S=mudHczcX+PR_n4^x zlX*VGvp~>{yr5w50ODkPaPz2Jwhme(6h;v)<4GMwggiu9+)a&G?#|+ya zSN;KC;61lEk3*qo0A|s{XEKYed52t<0pm+Yb|}E{-Pt-dKqHELhA`?~NqP$jbYjv@ zC3PH1`kZ#7^Lf|Yg5`YerKl!~+j<{=mJ-q;ow-^wY9Bt$_Pqe; z`MQ}F`g^@t7c;S%rPuX zEcO4d*aQ2ypZe0cUl|#HW;DMoi>&_B-5gEqjP-4F9Dlpp%etB3zi`?Gz%$aH(`EEa z2grPnR8QxTec91;m$SU!4w%ApSu`X&xY#S1C$dZ`KLpJ)BDk&HpJg0>D(em)S)NH^ zJA4z(|LC#S`FKn0$VTJkUC$?|hyIxf9AA zTJH=1YnT32OKR&-j78cP$KRpm3uBdaCgVy{-(@vw z-%m26*pp&bJ@}ZfVczbPJXAJJLI29&0jjXImH%QjYo3wm&?@RzcrO3~X@A^!_yz8w z@N?kLOU2w*e-v8Ne@+muUQ^1GvV}KXWqwZu_Z(Ze!zFSe zFdT0?ufgaeFIS>Vw!e%@Y32}XW;H^vk0+ldoo)NF*{Y))*ik~&wAk;Nt>&=qN3W$i=N;Lm>x{SGami`q zpoemHgx5>2s6?<>Yo6WWUpKJ)FtX=O%$+8Fp%%dZD}#Q!561#ONH`#IGe|L3n|nrQOE^t z;>qdIu))>*;}wq`Nhw|`ZFYlTTv3BtC8gmof$W0YaP67{!p_@RJi_11q+Nnd&1QYwXy=B;+#}{OH@Wa=i@RP_E}Kp-H+ zJSqQBjc0zT#^-62y3H?8;r%mI{yirBRmn4O_@5H^7WvF3KVkKqlGd2z6r0zLFWN@d zvijnueV8QcsZOa4+g=S#`Jk#D*$R z3Od_-axz!n+6i6@LRI)^7r`_9$ygHG*2xMzO1e02E90AW;2P9wsPxgpU_!k+PqjLK zQvp^e>~c6sW7<`ePW~uJjOGmalnM4Rxc|7$w4_+^3vg+fGOVuBrXh7!f+M{aP;LHm zI&IgU86;i#2WDOXr2=)U_2gpkOCf%Up8JDS-|79qsrP?z>Zo{{{G-2wpxfwkvV?GX6Y+oUa#hn!*9#Hhd< z9J9Qga;65m3$Kz2yie(YXnK;`WtNmDHExS(&~sf$=IYIw7Mhj4gE1u%>d`aPgoeMI z0X%YJajI&qK+qr~4M@Zo3hKABHs2T85DyoI&Lg_RvMmfKSk7+SL9lOxUR~#6-?6{S zT>0#9`#IC2a&`BP^x)L;{pbj5tZFV6@q-cnvb**pYnpUOjASSdhbGE(kB#P(8IVIK z_BKa|;JWOl{>R+Xz;s1~)bvR{Rrp7P%4Byx{URpCnKyZ(OP$}+Wz^8Kg6$ag5`SacaCM_8m(qfU3de@vO1Bb z|Aa(Q%wF)&_+>e#;kePNO0!?XueEMhIvY3r9@pJk$y0kK%@y?pbkE00jMdX03em3% z&q~p4=})Dol&$~pr&7fG=NMKTY4opWIX?fVJT*rhJ3V87rTOn-VGfOn9{n@1ddW5X z_dG*QRddQ&=iH-0O{tWdySs%7w~d>Hff_Ey8OGYG2qfZ<+4@nLB4V1|UC((9te8e@ zRT!dc=I&$>0W`bfku*E<5w+wIdD$NqE;2&zmGCSgTkS-BxO1t4!Cyx>7!sY|^$L*M zZ)8etgOLZF!)*g zZrYZuOa4va4ZT<+DO?S8*LoZ0+uOmjb4+dR+sR9-!zQ!UNBR}@Ou?Y{#9}dIvfn*X zxvibo_i8X%P`DwWu`pSE{k?)5pZ57%7W1z#l3Pqmrsp_$>TiFXZJE(UGP{QA0M6HX zE}W-KEoz%^SIQj1S&~CH7OzvBC$Gz08F}utyr8+fH5YMLU2|Ne2@rMHSlC~QMSbBq zo=URxxcNFeXJU8kkz3O1aG5{7n0@3vgog2r|HgiMOscU(RQEpQ@+z0JBIZJ`5%J4| zOtf~(Ly3AF3$;XNK~Z`tJ>o%EP^_3-LlE=>{<=7B!{t=pJ!+Yj>&3XAbZgAwdNci8 z@}u=Gj`}ccn~7P9_IfCji{S~&R0G?kyhXFuQ?F&A&ZV8MD60!$)9~3p2w9}G;KDQY@mqr+EIciWVn$@VAl;kG?VbJcnB8xOOwt}!kiCjkm~ zNtPVKFmq7{yZf#^2Pp@PZy7c`I3I#AuCtU&wVFKK*Ejh*6q#y%1le4j?{Up?a9n9y z#%)QK$V0a-XlffR+LWB`@DsBnZlmpT?T}v#FnPMOoAvCb&Zoz-wAP&%8-_|- z#&k(~38lAMZK_@Na)zdv{kRyt#YLsuzP_55eC+IfjJ=Tkr#F8U9y~jT7CH;-ft4Qa zI;VGpEDlnpHEAmuaAB8PP&gmDm#N#$G=ot=P@IBtL3$>beD$QZD#!#xMD@yP~oJCvzxR=L@c{Y6a;zcR#9YkU`mV;V>_gY(U>j9Kx<} zufg?dPGbQq?CbWv){IP1NzrHR@Y>aRH5jBjaoBr&Kdc|&2o8v~;>W4m{WhaW1wtmy z>50SUwo4*N22)#uFALyyoODAeuS?6R>>CNEQm(uQ0+c6&|A6T~d-xs5RH}^>AH0DU zPdWbxysnByVQFo{Dd8!<%BeZpb5!D~a&g^^MYiAkezqOglLMe~7T^Dpu5GUII5RD+ z;eIfvT$ZBow6Zy-Wk~zDNqj$X*F&qZ)O0e2%I&^>>Q_b`Lcx>&a3}p;K0Hn1eMWtK zeYpys{1(~XnMDh-Z>4JTOz*f>GIkb6m^pa0?rS0Vxxj82dledHNfK*;abyJ;OkQ7l z`K6oWEOkbIq18_N*`o73I=1;p^BPyVWl(f5Z>s%yl#iYL@#KSg`is0S@OWaAimO)! z2PP>R!zXh)K}~N%dFPJn56ZXSUHL{gPH`5qEuw=V*kNN}=;)3~BGKwA#=YVM$i6wl zTF%}CC$5$mE@yKY3(=`-lP|&vNsj>U zo{HGG`VcK86s#y=eSCa_(Vv_93Ik`~uWxa>D{I4Fo2%NMMDKIuzz#bun}`9q5WE2P zPS_DciYXz|Jw~?4{8}*j$_JP05I$pR$ci!N5EcV$hauctG=@(4cDB8E#7${{q@abVn$oJ4#mPW&Q*@vFde}^X$ZG@W zFWx&gA)y-ZCp4h1_-e=IB27>jIXPX-d)uLW>TR*4t{1$C<~Ky))-!~R-X=^-4ps6i zMwMp=b1J9J zjg&i#_vHs-LA&JM!>kw+Y@?HivTs3V^jF9X>$zQKLv-EL1KQD#r}o9*FXct_7-PEFa?NC!WWLSCuLLGS@RUqakQkf6G{?|rXsD?a z=L{#~dP7)NR#$K;H=eWt4sJ+q^ViKnzQ9{Q$T%|5PY?wfQ=Wc)l}#7tD}$O5^aY)w z?dCXM2ySbnU!<6izt&u}@QBFX-LtaJHQ$P(CWHuHLn_zZA5MQ9$$6!{8NCp6AH?tU zYcj7-wq{+zkMBDRA?x~ct3|cbSs9{m*tw(o1Mn`lNRgii?eO||7ae)cNizdf(DIU^ z-8j7Bh9E&Gyjc3vk#%hD|!AAyDOlgSCwZ)$fU(m(Q=v?q%?>vcEZVjzMLWF7IOf z6zU5h`U9VR3yj@8G-y-}WUiFH@BI#TLjkHhc0p*GJ?A(i#*eiXnw6Tm@Lo4=b0X6y zt&R)OkMwrR$ea;#8OW!(pX70d@QpuOi)R4$sBVS@bY<-7D=>nWNp?O1PKbI$T_-3J}ewUce>? zfPeUIqSxy7`8n$2^!bS%FDq9cxqFIHZ;?sR5{0Z|&qt)n6^@&+ov&BWN z?W}s?>ujY}6A5F!w1Y!zzSLR{yaCr39618eIedrwdq{c+5Y1QYxdRiHh2?YBtb=JA z&)E^j$pyi?bR*G3fe{c_19m%1;f0Zn_FFF9myx^;hQ;|oWp4_6)OE5a+EFJ(r6WH0 z2sqGpxwh4LF&h>ZvfLN)ch%$eM6!kG8anY0yCr;hf8fKrSxzGeJq42C{mr^O*Pp&m z2RGnV*N!bKg?3BDb6P2p%s8xT2NC+wXIN6Gz9qW@lGG624OSuwx~R_AkQf)N>dYeS zb)N$}nF1xrCZfQ$qlzgeB7 zY^XMmLNet(_6K|6iP@6046^Xlva6+{w~U)Y)kJqMVAzp}AU!<6qT4~TL1Vk}4>vX% zLAMqqa9co#F3@#DH>U?;eFsC4=^>)bibeO4$lH%oYbgnFMVa{2GP?lh?PjQmIA|>q z0PU_^r$?`8)N4NM;;~@wK52lcKSB0HMecz!8u(079y6K90n}5muio&RYt=VE0zy;eQ!Dx*+eORi^ zb(Py!BFgP3K$;D5#wk7Rl?xMNthyTtz6l1M&)4WAFEQI;N#7Ma9*ZvE-sUVgRI(8k z;q<(Fm@wL_;hqGCry_^8xWHE5lj(swd;2Fr-TSO7THzfyaZFec>ie}zHvB(eB=Ah z_YklB*>6a2((EpsYU2*-797*i!)P~iAx<3Bt?~?qcw5ue`Ipt_hhHZK_wtk%htk!yQQMl& zZ1;P6cLzO-f#ZX9O1KL*)0eAS9@aUv6|EQIlyx&{OE+I)jW^?2qNZ2X?&dE&)i>jS zrk8N>H8pn(O>XYHWAPs4SCsp0WuOcBgQy_v%VOk(PFYnCQN1+5j@@C z?YrV;Us)`?RaGrs)L<<($gJ3(-p~Sp#m5rqJbgN?kb~GTC1F@36{hxuYb1Sa*^-)C zJPKVbKF^S_>sGj)<5Dt*&?gX=lCkGs@y8t&oGjTJmo4F9i|Q>T_&^OTpA`B5mYCn; zWirM=f^8|iKOQA?#Rg-ynjVDaD8mI_IaMP%3wl(_#)(C?<0oOagcN47AeP&09etNJ zjec~TKXC3G4VPt7!(+A4s+4|Ep1QD7KYGj^-$uD>7NF_MaC#TkLpX(vOHM66{L#D7 zLK1(fC7R1lff%ns`oSV1$ls#Dz}`AP1}4(#?0upnS&uXOb#6C8h|2v+XnKcfO{L3$b?6}q7n$|286;6oaCVDWzoD@ zl+L3$`~<^=fTj!<{X_|(WU20@)9L^(SVCg`J&zILlfPV-uBc`W?6AdsKW25r z;mW9>#qGBVqRo>}*X0gYU(eUNlgMt|6Z5MKk`!Tyjj=?hA0PGV)@>zER+2TL>(h+P>Fk@M;-H#0k%rw|kKSu-xuBotDhT{u|`blz+)KVP}F zVRUTi%pTBtE-zLjsyEO{o*Ex%``!9EZeo9>qdyUOf`%cygWG<7gXFm}j2*1I180!= zeeL>ELIJDNgANh7FR5%3Ojal2#!Ev1ZN=S)m2FMivdi-PLllb8d6- zjJ}X=$4Q%nA`ID5KlA(RRTu7Tq~6V$vlVqTN%aw~9J;r)QP(S-H`8Z{w5SkiaW>c} zLLn%&rJXWk)6D~Z^huNr$*7RZG~1FiA;B7hd9|HZy*+LsJJtc{3aU$m}yD0!Vh&p4Fr`oXX2~ zo$x5@lwZipJfGqe(PD0a3_$HI;Lw9-B9QhRXzTW7AEb724nFE^5FWzv?8jo{@cPd3}E;$ke0UbBd)qQDA!3G2ppfBDk zgRMODFR0a>_2+~uF>}|Q85!LIV^0@wQ#OGtS}Fxpo|dlu%Gn~9cs2W5#Zq+A@H z<$Kh1=9QPTj>(z`A(3megLK79WXgAEIFHdAbP_DXV82q~XC+;M6RK%irIJ-iPuZq2 zXRheR`wK8wcj~1r%A-A8j~@5hiOdB%^+qO)o;QOX$shLGCaeDC~!i z(a_ftIrTOHo3+Zyv`P_{t&as1T-kIBP*{rL0VHxbE1dtvvDuuk= zb3uYTW*sSaEf$jZ zy`2vp7==iL{rk#RSXTPpm=4M`l;MFKZbnc?^fyHZjF7mPrrC*Pk@g*Wk-Cuy@^T9x z`>lB0{_iaC6Xh>XFGQRq{iJ0pJbK|Nzd`k9ybdntMsUI&l-lb~!R!2%{VwM2L)Vz- zw^f|e=UyZMn`w1EJbnuX?BOX&NK_Tn-Bx6RLypW9@A*sQ``cF59AjELF3Qx~Eiv~gk#snXGK>oOoeV-$RqR9(H zRR~%@h1KD!kC>$J87crKwO)!9yEUc zJoqs!&g>J9gmMvNDZWbhKuN6)BpJ|`?jiP5$cV)z2wFd{VuXf6GMv81_2T)`550;U z=a-M}7GZGOVf_r=U#9^L#xb3q1Uu~aRyr&#>Dfs414aJeVaST=;IEX3xiXEV1bxZ+ zWA!wzbV0N2#+mwXR~~=v?8XUrUwNQB3*gU!_P=&^+5Rkbr#SQVf zQ}%uP_mtj>_V)JI7Z!IORc{yOctx`DK1SAyd=@cfqRVCnq@{Q(B=nIfDf)x>7}JZ%D~dXe_=uJn>-Atg+eS3z`$0r$yCo7isSd(`s6Q)P}u@uH7Of7jC36Vh$xs?44O~(01NZsJt-ObmEH5 z&t=_bOUs)Bg+&ckSNrD&RTHa2^<9ZPL+NWo-2+6Dm&kdQ>7z;ga}!V(oM&->nz50!tREs~ z2OTDshey*B!M!tc7hATk3f*k#8$4W(YP`AUJl^Rn9({e*pzfaOie7Wsms>NIkCg@c zX=$GYV>1e`oc0C93>(S@(9gl@Vr6(=JC(@Zf;0VW>|iZhliPaXGM?pUb4L$evc@M3 z-sn$~NRVT&%Z^GDYMd99wlfnPLUC#uydJR?SId3ZNh$9{4*U95 z_EJkY8!u-+)vfIfn1`-?`m+7))RnQn*T`_!%PhIk;i!GBGpwmxqd{$eFm=CIxe&jA zV_8zq1P~S!vEI@cZ657Q!`a)wp8I|>4j5p5sXEkAa9j`QP&bO+35TZtR>0%3BeOBB zT!c5>7>drO6`!KT?dH5O*4{l;@bi3#X1)UncQ@|bq+9P2=#E^&h&n! zES1j2k^P}m>2u{{h2|MH$+8&j0i_tsRV9X$#!upv3ATbW?qxZb+CR_Vo-toIs9e_{ z`GzpERh=ISIx=-?>RA}M?5{K`CkX(~hCWjE_lxz6r^TS4*7 z+W4!(xjSmvOoXHwW{Nv=@NSfy;EW3|M(gFUp`wTvv^=___PsXq-cRc zPeI?h7aC7ch}8PxI=AKCb<|nsGq=KJR~8l^VSQ&-*Lcfv(i1h(dLlhmuKnErzw)4W zm$1>YB+Q&Se(J2pTh|a?gEFyOiIYAkqJBADm=oke|?Q^@Ok_>o%3&8BjU3?bo z6k&}!6mBT&zLY^Z&H!a${$eDEiHjnLu557C4d21Qn3O5mHN5Z37bK!L zv+AFXW&36&O@m@pNO;nq6x9N=6}_yLIT+8nf{HqVp$};{h5F++*J>_|f}N2WHvndq zFak%fgsF~1#^a+UTS@QlzyY|P^&ujfCdTu$edV4<7nT`JX-VF-2^Li06g98rMRDWZj-8 zb8zcet~mPwH_b&WWcEeDoKbU~^06osAy)|&(mQP@En4lP(SlS@N4ni$=-H-nJoxIO z6TnG3+t|&QfeqNr>hpz3kDIqz9N@JLoV1{|Ck=TKAfyH! z?P_g7L0laHIRM;H0IeuqWuBsUJ=d#F{`LGL9Lyd|=vvgV> z9cOla`v#~6voM5&g|7%Op<_4E2{55zw{Kn_#IE1GLSoBo*oi@CpU+yk?L7y2*j#xW z4nP6$dSW6)ROO@F{QhvTKbpbvQF%?x(Fq-WB4?lFd_&CwK)Gvc_FPYteWg+jOVeFA zVTyXY7^1mxm>$V+Tp8;TBCOQT`)YRXGIxW$;_&8vHXwuaw}4vwXy=ngzwRU8kRxnQ zL;5ad!TxIiQ53`ccK@e8ojPzubP=lM8PDOv>q1K&!~QS44o3SkX%JNQ?(E#_kh_94P?J6aYh40Ms(HrL!Jg$Y@=%S=UuyBA+cetu8zMd zC@R{l%$?4HF@rLOz#)HO9%_=;Phb*DUBSBjT(sXW+z3<7JmfhahU{2zL~DQ-$Aq~q zZriZ0he7`1m(8mXc(YGoQ{xw{77G^>g3D|-PlEDtvSf(mP>B^rJBQ)NrHs~RpR;^k zZ#l}ZXss6{IF8EftMux6@cbdI37TkUEkFM*J{p1S2ZAVs&VEm7GCvc(fE-AL*RV}a zx&{_*6>NxW@PghD1gM^YK?ECz73r0FjA?lG)Yk;7uG8x1VV1)$?FfO@z|x?I z_4y4_zR%GSoYa#fKmfH-eCm2FUHmg7+sTs+=@kfX0jL@Ea$%SjQYj;$aw*5yV&nND z2n4t1L&0rKbiG4Jv_iT3pWa~B)UdEtxi{qmlh@+nlCMPzL-KJx5uHTRd61gUp9f&c z_IL9jf)W&d0j16+Oc6v6K!Tsr<)Z?m**Bv;VGUqs^x;Ppz3#VDT9Cdjk*{ z*UbPS)T0cz0)m2lN#531@sq|B0m8VVfMt%0zFhh zbd*@EB+hi^`&}Z5===KIO;54pnI2eSIc?8g<|fdLAZ{XN8(0(~xdZkyzc!Op`g-c{ zE$|^*2jgH0%R-S?MnHOsc(&&vu*PZyy=|Gw*pA&e|Q5+F*_WFinDwxE%IQ?{%K$gj^_4c4N;Abl3YXg9M>x} zY~2}K8uX_s0r)wpf(?ui{ub$2qkE>&c`#HO&)`&1+kDa24J@(?kX65D6lk?ZW(KC% zyKjU)jtt$|3m;>=S;INgGMP5)ybDDY*JBWA9C-mF#NJb1$|yN1%-B0JNA8d#&V!X{(`i7Rp%8)vYfIS~{R|dE7gwFFBt3{f$o2rLh)9@> z$myyYAf=GDn**IKK!#%)`f)}av87NUDb1AGge?zpvxAn};-&PCu(On&l7WcAsX6M+ z?-dTp;Z2e2b5d_XtSiRlL(4}`I)CTTS80AKL|>$k&M2`oLMbz^LgoARGa_I0=fVTu@_pA z*v7l9J1EacZA=C)FRk3phkc*xsMxgjc$+$|L7EKqsq8Xms(SihRx=aH3$FsaNvrTe zJPfp;Huz?o4k;g-+ za96YUTEk#5=h`|7!>IL^z=vPPR_a=GSh35Ut}al)D)+3RP0JJ=Aq_GeWX#_7M2uHC z5*rcDWEdS9B8b{r*vV~ctClGyx)3pDZUP#R1VLpxRI5e3?wAWHr8JVzRG_pqP04fD zw+go}Nos3(L%r8aF4(9+l02aw&*kvZLr*SNB(d*Ngt^w3m@FS!T1Y7O_%$8u)eiNnRv6H$|`h7!!j|RJ}Z8Relb$pV)>M`Ov z5-+YG8ze58Q+uV^wbY45VMv6dMUl(BZ z+S~nS)rYi?kAPpTd*gDTE%Jq=3I)hKu|sDfXsM*%9)tvp32UW zI)CzdgN>LkQ-sEC(H=BCft;Na3rAx58FeAVMUzmts~r`F_C#Co<$&0J#<9Aye~FNx zc)4Q&aN|f1!B!9R=W`#8 znVABU;@H6U4Ec%7*th!-)AaDJaGfIPF0AwdA1-i2DR^k>inkP$+v!jd>*N5b{rROK zWk}J+ZA+0C7JO9HPIN49XZgwO$A_6nQsKskyNqUQ`abB*S?7zC7dg27K-6N$XMWAL zV>^b7v%$X68QwRCBUCv-MmD3?&`~J+U`QJC$&!_>t%PsHJGxr#h4SOWtRr7!JC$k5 zgLYZegbdb8+HR>w2FcjYI1|stS!C3sA@`@H`X)_=2hrHg5nYSYqiCWBqNaS$&8eO2 z-6e9~Ru?z2zwXXIxC$B3l9@1<$?+o2wyZD%Hwo_NmyZo2bi$1h;L$HX}u~IvoBl(PUEvz zV@^^ALObSsCp-+;OCb(ot3m&wHQyq*uNx*Hw5B7lh;|CBmxK z9*;uj>D4W?7cXrNC72bg_gLOb*evPgAS}5o!Q5zEmI-O14L^<H=M_Q~rNn^Do!WJiNb-8UhZ0JNpMfa_%7y zpvQTeGAs>{{QA#{KCf53gTtO@%$3d}FTqL7vj05yFl*XQHNZ@Gs}jlq21~|ah2OIn zk^ooVyp4S^)ym8k!}-Yradl^5T{hI4da+}>04kI?4n zWKAMPHuPt^hH34kk}A3o#6!gG{XLTkDoLbOe*|ZF`w2~s&?v#SoQ3tNv)g}A!{uqw zNN`9_fMSrUHR=n~~Nph#A_?W@<#*!&;jW3b}=#`Lkxglkp84 zJ;;FB=i*&@QW%@y?-OtGX{Aj{x2YiE1GXx@y}>k0BnQ8e_G1phFA76J%?uL$^O!*# zbyf*tA1<^#U3hItBQBS$d)I{@I2Jv7N`jU$iZN3Cno*Joj#OV|sQz=sIy7aLC!2n& z0`K@$R1+etJEsqU zXPi$h^QwQmr|i9|A3pd@;!JQFWw{Zn-5D0A1~38Wy<8WdXkjl(Yd+A4&L@Bpo@L== zs`>E#L3H1(DIm(#OR3zNucNi>_O}W--XB zW-k+3&M^v|O@5HAeMCPgooM+CoVbp(8hy0b0;1;aObd9Z){sQqF|Fv zJl4l&62@BzP{DMPq$0@(x0rdWGfhulL078jRll!=kAF?tK8!vEbU#f$EZ@cb#V7yS zNjN!v6D(QKX&E$!K)8nxc2$TEBalZrL!IoHn6)Nb9zHeq5%8d?UTxojO zlSvHNE%|eaPZC=O8jyW)DcU4#=XV60(nc)`xhoAIlRS7l=-vv%p^F}{tokup zrcQ`5vIR~Po7m=rrdmG?6*NlZ{{$aTI!NkyepwKf!s8~nsKz~FzsD?|^1{`F%;k8q zMdqyjBUXd(kJa7EVKrT2XDzPSoe$TW1;4>1*Ch?>C3#GX)|94R7-&*MnwZu`!%yTvbhaR?+jqR?iRxv`7gN5@0sGMAGoXqm5JZ5kNy_4;Y zrl|D~oEoZCAN@eOn?R~|mW~l@$@HJ&15XVDcb~LN*jgJLOJHPO=+^SqMG)}Df`Tv> zJe*>Q64WW9zI3`QYrxhn&&@gWhp((H$p}srek^R*ri`19ilRF6n*UhH=?Jh+SE|Cp z+UL`teMI*5Q@N8gCzr%>pS2%zt@Y0_tDM#!`Fqhag}P08mpNC_$5icz=@v6x)2aE# zih?_N+!uY;fN87fJwdv;HyTN`4p;Arr->Ur#-4IY=0(PQ+%KiAN}sW*;Jgf1$v)ED zU_Y~9ontPEsaNL0{!)lZf$1O-{d0zHPSWDN-Noc#ExGeL+ri18`asbzUB(g1h9$yH zg>I_U)O!uU68R55{gi-Nm6>gW`qxLzmhnBf|B0}?G#&s&SdIqE&O3pEa&CI^pGTs< z0w(Nj^=-^`EOZR@Z&R@TPyJlP6gyMUMXy5vM~yV_Ufvmdyh`;eL56}->ZEzCgH%|5 z5gUU$Zdm1<6^&6g9BKy;PCR~v%9zlGs)l`nU_QF)ihp7sP)La=jCvvWkVKBZJE*2O zMfC@bZcXGQBU@0WV+56qkT_KXCdH;D@4H`gmT>JvnYA$qVW*no0=x-A)k4#Y?_av{ zE6e>-#nY`no7%jfWJ9#^8j0|8(C;c!I;b8p>3vqv@C31#QzM%#l!F7gC$q2<%2{bb zCcX%T+eKD7C?LAJEajtaBm8M%k-4FbNqQQ5_CyI$1036F18YI*eAxM_*|LG#ak!fW zwUeS^)Sh5u`Ok~`9Eo-`OysK<8oi|@EJ+R%HnWt(JnoiG-*b3l3wh_A>7wLMMt3U- z&A)yTmF8rpH(iXQ@>4w13ZwhgiKlwL#Y;dU(6wh&#})6dH}k_TJbqm$&Ho}nG%CqQ z8vXBXeSYKq5OeB#c4BbIT5*kkP>S;6 zp|h@CvKwYXS6zL$#1nDV7q*rqM+AnsyjC#lQe;&C={M2`C5iEunPH|{sFq{6FDHs7 zc}FTGcV9954&ZWE?WK?X9aVT;VF+?5$_}J==%BX0Y2klxshbb~8jEiRVz&GpiQ^xh z?*A)h@a|ONuXLfe#~4DVKl z`AgMm4N1+?0ed=%%u!g8#Bw8de)Y^OG)zaj_(G?t*aVr0M;5i*6EY&W45jgJB3|xi z3wL~~Fx`8`J&m0|v_mPRxUR)U`O9`s_0DpZ{zxd$EVuk0_79-*KR(>M3k5PC2UBKK zz5lu{~%rUKUj1?GaMbO9y!`CT%+h;EPsx3%t> z?&q!)c={1gj+oyi!%Osri*{S;UuBHBD+r!`0+iL{cggUAz2WiR5&Rc9PQdj*863cK zJAjf}{4N<@jyI9hf9m};iNimnxVS3-o}1yeVFV$9nI4$Z|2<&@xE3he130#r=vHND zZXPawO8l$b58z@TD+I^bf`;GUCBw`0$z8GgbCJQ-K>h^|GQHi5Q#XOfx2twvP%gL@ zsAk|)OisqjC)t>exTI5O5p6o+a2~6|E|)#nVaBZpe6+8^xYmda&B_(+-|~q z!Wr*Mfn(in+eYq9bKaJ^KL+rw8aNgVG?V{bGQ0p!|Dtw(aNJ!va0nKNHTJt?c%hTs zmAeml?5++t^9VGP{arG=BFXRS+zYUER|s_D-?*dOzJ*M6SLnV#C2%c}Z&ia4Z*FV3 z{6*`&I3;i`kiml^Q*PVE3eDYm{R^TFxE!cz;3SRP!^WclKx%YWj3VfsEwv?{kU8#F+VBM7hUwq&8D-r#> zQvYHf<*pp~dh_-;NMLwZ?q2KryF%b@b$e`zGrB8u-^J`*E$~&)?I$Fh@m;O^FJ)yV UVSZtYL3dWU$ss#w0;=2p1CsO`=Kufz diff --git a/tools/conv.py b/tools/conv.py index 541a0b75d..f483ae1ab 100644 --- a/tools/conv.py +++ b/tools/conv.py @@ -133,6 +133,10 @@ def migrate_db(file: str, schema: str, exclude_tables: List[str] = []): for table in tables: tableName = table[0] + print(f"Migrating table {tableName}") + # hard coded skip for dbversions (already produced during startup) + if tableName == "dbversions": + continue if tableName in exclude_tables: continue @@ -156,7 +160,7 @@ def build_insert_query(schema, tableName, columns): def to_column_type(columnType): if columnType == "TIMESTAMP": return "to_timestamp(%s)" - if columnType == "BOOLEAN": + if columnType in ["BOOLEAN", "BOOL"]: return "%s::boolean" return "%s" From d168a70d09ff2f1409be26ff5306e9caa4399b6d Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 30 Nov 2022 16:28:48 +0100 Subject: [PATCH 2/3] remove codecov --- .github/codecov.yml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .github/codecov.yml diff --git a/.github/codecov.yml b/.github/codecov.yml deleted file mode 100644 index e190e6aa8..000000000 --- a/.github/codecov.yml +++ /dev/null @@ -1,9 +0,0 @@ -coverage: - status: - patch: off - project: - default: - target: auto - # adjust accordingly based on how flaky your tests are - # this allows a 10% drop from the previous base commit coverage - threshold: 10% \ No newline at end of file From 2335f7926128d18f21d1ee9bd6b5efd578815877 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 30 Nov 2022 16:29:29 +0100 Subject: [PATCH 3/3] remove debug print --- lnbits/commands.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lnbits/commands.py b/lnbits/commands.py index 897390768..a519405a4 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -72,7 +72,6 @@ async def migrate_databases(): version = int(match.group(1)) if version > current_versions.get(db_name, 0): logger.debug(f"running migration {db_name}.{version}") - logger.debug(f"db = {db}") await migrate(db) if db.schema == None: