From 64028d559f8a302e2d1a0535ccfca4cbdb6e0930 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 7 Oct 2022 21:53:04 +0300 Subject: [PATCH 1/9] feat: add `MINT_URL` env var for 3rd party mints --- .env.example | 1 + cashu/core/settings.py | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 78504b0..2348d62 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ CASHU_DIR=~/.cashu # WALLET +# MINT_URL=http://localhost:8000/cashu/api/v1/cashu/SUVB2UrJSd9LKmn6aoSpVq MINT_HOST=127.0.0.1 MINT_PORT=3338 diff --git a/cashu/core/settings.py b/cashu/core/settings.py index 5a95fbf..b7b2ccd 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -34,13 +34,15 @@ MINT_PRIVATE_KEY = env.str("MINT_PRIVATE_KEY", default=None) MINT_SERVER_HOST = env.str("MINT_SERVER_HOST", default="127.0.0.1") MINT_SERVER_PORT = env.int("MINT_SERVER_PORT", default=3338) +MINT_URL = env.str("MINT_URL") MINT_HOST = env.str("MINT_HOST", default="8333.space") MINT_PORT = env.int("MINT_PORT", default=3338) -if MINT_HOST in ["localhost", "127.0.0.1"]: - MINT_URL = f"http://{MINT_HOST}:{MINT_PORT}" -else: - MINT_URL = f"https://{MINT_HOST}:{MINT_PORT}" +if not MINT_URL: + if MINT_HOST in ["localhost", "127.0.0.1"]: + MINT_URL = f"http://{MINT_HOST}:{MINT_PORT}" + else: + MINT_URL = f"https://{MINT_HOST}:{MINT_PORT}" LNBITS_ENDPOINT = env.str("LNBITS_ENDPOINT", default=None) LNBITS_KEY = env.str("LNBITS_KEY", default=None) From 80bd3c6d3a0f34b67394357ed4158b7204223975 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 7 Oct 2022 22:26:38 +0300 Subject: [PATCH 2/9] fix: check requested amount against the paid invoice amount --- cashu/mint/ledger.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 501eaa4..26f6ee1 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -187,11 +187,14 @@ class Ledger: ) return payment_request, checking_id - async def _check_lightning_invoice(self, payment_hash: str): + async def _check_lightning_invoice(self, amounts, payment_hash: str): """Checks with the Lightning backend whether an invoice with this payment_hash was paid.""" invoice: Invoice = await get_lightning_invoice(payment_hash, db=self.db) if invoice.issued: raise Exception("tokens already issued for this invoice.") + total_requested = sum([amount for amount in amounts]) + if total_requested > invoice.amount: + raise Exception(f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}") status = await WALLET.get_invoice_status(payment_hash) if status.paid: await update_lightning_invoice(payment_hash, issued=True, db=self.db) @@ -237,9 +240,9 @@ class Ledger: # check if lightning invoice was paid if LIGHTNING: try: - paid = await self._check_lightning_invoice(payment_hash) - except: - raise Exception("could not check invoice.") + paid = await self._check_lightning_invoice(amounts, payment_hash) + except Exception as e: + raise Exception("could not check invoice: " + str(e)) if not paid: raise Exception("Lightning invoice not paid yet.") From b0f71b0c67521d829e54dfd8c642ad2594d9bec5 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 7 Oct 2022 22:52:50 +0300 Subject: [PATCH 3/9] fix: add `raise_for_status` call after HTTP calls --- cashu/wallet/wallet.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py index 719ffee..b32421a 100644 --- a/cashu/wallet/wallet.py +++ b/cashu/wallet/wallet.py @@ -45,10 +45,12 @@ class LedgerAPI: @staticmethod def _get_keys(url): - resp = requests.get(url + "/keys").json() + resp = requests.get(url + "/keys") + resp.raise_for_status() + data = resp.json() return { int(amt): PublicKey(bytes.fromhex(val), raw=True) - for amt, val in resp.items() + for amt, val in data.items() } @staticmethod @@ -88,6 +90,7 @@ class LedgerAPI: def request_mint(self, amount): """Requests a mint from the server and returns Lightning invoice.""" r = requests.get(self.url + "/mint", params={"amount": amount}) + r.raise_for_status() return r.json() @staticmethod @@ -130,13 +133,11 @@ class LedgerAPI: json=payloads.dict(), params={"payment_hash": payment_hash}, ) + resp.raise_for_status() try: promises_list = resp.json() except: - if resp.status_code >= 300: - raise Exception(f"Error: {f'mint returned {resp.status_code}'}") - else: - raise Exception("Unkown mint error.") + raise Exception("Unkown mint error.") if "error" in promises_list: raise Exception("Error: {}".format(promises_list["error"])) @@ -180,14 +181,11 @@ class LedgerAPI: self.url + "/split", json=split_payload.dict(), ) - + resp.raise_for_status() try: promises_dict = resp.json() except: - if resp.status_code >= 300: - raise Exception(f"Error: {f'mint returned {resp.status_code}'}") - else: - raise Exception("Unkown mint error.") + raise Exception("Unkown mint error.") if "error" in promises_dict: raise Exception("Mint Error: {}".format(promises_dict["error"])) promises_fst = [BlindedSignature.from_dict(p) for p in promises_dict["fst"]] @@ -204,28 +202,36 @@ class LedgerAPI: async def check_spendable(self, proofs: List[Proof]): payload = CheckRequest(proofs=proofs) - return_dict = requests.post( + resp = requests.post( self.url + "/check", json=payload.dict(), - ).json() - + ) + resp.raise_for_status() + return_dict = resp.json() + return return_dict async def check_fees(self, payment_request: str): """Checks whether the Lightning payment is internal.""" payload = CheckFeesRequest(pr=payment_request) - return_dict = requests.post( + resp = requests.post( self.url + "/checkfees", json=payload.dict(), - ).json() + ) + resp.raise_for_status() + + return_dict = resp.json() return return_dict async def pay_lightning(self, proofs: List[Proof], invoice: str): payload = MeltRequest(proofs=proofs, invoice=invoice) - return_dict = requests.post( + resp = requests.post( self.url + "/melt", json=payload.dict(), - ).json() + ) + resp.raise_for_status() + + return_dict = resp.json() return return_dict From eca9e95d3e862fab867c7d3b193d6fc6f49b4344 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 7 Oct 2022 22:53:34 +0300 Subject: [PATCH 4/9] fix: falsely reporting `Invoice paid` --- cashu/wallet/cli.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cashu/wallet/cli.py b/cashu/wallet/cli.py index 39086ac..b11d9b1 100755 --- a/cashu/wallet/cli.py +++ b/cashu/wallet/cli.py @@ -104,12 +104,13 @@ async def mint(ctx, amount: int, hash: str): time.sleep(3) try: await wallet.mint(amount, r["hash"]) + paid = True + print("Invoice paid.") except Exception as e: + print(str(e)) if str(e) == "Error: Lightning invoice not paid yet.": print(".", end="", flush=True) continue - paid = True - print(" Invoice paid.") elif amount and hash: await wallet.mint(amount, hash) wallet.status() From 118f564d44b5e77040174b6d27f943ba47ab72fa Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:44:14 +0200 Subject: [PATCH 5/9] Update .env.example --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 2348d62..2b58494 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ CASHU_DIR=~/.cashu # WALLET -# MINT_URL=http://localhost:8000/cashu/api/v1/cashu/SUVB2UrJSd9LKmn6aoSpVq +# MINT_URL=https://localhost:3338 MINT_HOST=127.0.0.1 MINT_PORT=3338 From 2877e55838154274ddf413e2250db443ba03a772 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:47:13 +0200 Subject: [PATCH 6/9] Update cashu/core/settings.py --- cashu/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cashu/core/settings.py b/cashu/core/settings.py index b7b2ccd..6f98127 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -34,7 +34,7 @@ MINT_PRIVATE_KEY = env.str("MINT_PRIVATE_KEY", default=None) MINT_SERVER_HOST = env.str("MINT_SERVER_HOST", default="127.0.0.1") MINT_SERVER_PORT = env.int("MINT_SERVER_PORT", default=3338) -MINT_URL = env.str("MINT_URL") +MINT_URL = env.str("MINT_URL", default=None) MINT_HOST = env.str("MINT_HOST", default="8333.space") MINT_PORT = env.int("MINT_PORT", default=3338) From a265c93cd5d877f565a933e4d628e3830bf71e86 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:49:05 +0200 Subject: [PATCH 7/9] make format --- cashu/mint/ledger.py | 4 +++- cashu/mint/router.py | 6 +++++- cashu/wallet/wallet.py | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 26f6ee1..6895bf5 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -194,7 +194,9 @@ class Ledger: raise Exception("tokens already issued for this invoice.") total_requested = sum([amount for amount in amounts]) if total_requested > invoice.amount: - raise Exception(f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}") + raise Exception( + f"Requested amount too high: {total_requested}. Invoice amount: {invoice.amount}" + ) status = await WALLET.get_invoice_status(payment_hash) if status.paid: await update_lightning_invoice(payment_hash, issued=True, db=self.db) diff --git a/cashu/mint/router.py b/cashu/mint/router.py index fec009f..9974826 100644 --- a/cashu/mint/router.py +++ b/cashu/mint/router.py @@ -41,7 +41,11 @@ async def request_mint(amount: int = 0): @router.post("/mint") -async def mint(payloads: MintRequest, payment_hash: Union[str, None] = None): +async def mint( + payloads: MintRequest, + bolt11: Union[str, None] = None, + payment_hash: Union[str, None] = None, +): """ Requests the minting of tokens belonging to a paid payment request. diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py index b32421a..fc1fb84 100644 --- a/cashu/wallet/wallet.py +++ b/cashu/wallet/wallet.py @@ -208,7 +208,7 @@ class LedgerAPI: ) resp.raise_for_status() return_dict = resp.json() - + return return_dict async def check_fees(self, payment_request: str): @@ -230,7 +230,7 @@ class LedgerAPI: json=payload.dict(), ) resp.raise_for_status() - + return_dict = resp.json() return return_dict From 19742deb2e740b8f0f6fea93f338325c6ab0dcfc Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:49:48 +0200 Subject: [PATCH 8/9] bump version --- cashu/core/settings.py | 2 +- pyproject.toml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cashu/core/settings.py b/cashu/core/settings.py index 6f98127..68a74ba 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -48,4 +48,4 @@ LNBITS_ENDPOINT = env.str("LNBITS_ENDPOINT", default=None) LNBITS_KEY = env.str("LNBITS_KEY", default=None) MAX_ORDER = 64 -VERSION = "0.2.5" +VERSION = "0.2.6" diff --git a/pyproject.toml b/pyproject.toml index e20d5f0..62eb8f5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "cashu" -version = "0.2.5" +version = "0.2.6" description = "Ecash wallet and mint." authors = ["calle "] license = "MIT" diff --git a/setup.py b/setup.py index 27918cc..2cc3078 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ entry_points = {"console_scripts": ["cashu = cashu.wallet.cli:cli"]} setuptools.setup( name="cashu", - version="0.2.5", + version="0.2.6", description="Ecash wallet and mint with Bitcoin Lightning support", long_description=long_description, long_description_content_type="text/markdown", From e04da456245a3cf45aa2658d888a77a177954016 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:54:18 +0200 Subject: [PATCH 9/9] cli text --- cashu/wallet/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cashu/wallet/cli.py b/cashu/wallet/cli.py index b11d9b1..8ddd0e3 100755 --- a/cashu/wallet/cli.py +++ b/cashu/wallet/cli.py @@ -105,9 +105,9 @@ async def mint(ctx, amount: int, hash: str): try: await wallet.mint(amount, r["hash"]) paid = True - print("Invoice paid.") + print(" Invoice paid.") except Exception as e: - print(str(e)) + # TODO: user error codes! if str(e) == "Error: Lightning invoice not paid yet.": print(".", end="", flush=True) continue