diff --git a/.env.example b/.env.example
index 910a718..50c86d2 100644
--- a/.env.example
+++ b/.env.example
@@ -24,8 +24,8 @@ MINT_PRIVATE_KEY=supersecretprivatekey
# Supported: LNbitsWallet, FakeWallet
MINT_LIGHTNING_BACKEND=LNbitsWallet
-MINT_SERVER_HOST=127.0.0.1
-MINT_SERVER_PORT=3338
+MINT_LISTEN_HOST=127.0.0.1
+MINT_LISTEN_PORT=3338
LIGHTNING=TRUE
# fee to reserve in percent of the amount
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 6cd1c63..2ea696c 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -31,8 +31,8 @@ jobs:
env:
LIGHTNING: False
MINT_PRIVATE_KEY: "testingkey"
- MINT_SERVER_HOST: 0.0.0.0
- MINT_SERVER_PORT: 3337
+ MINT_LISTEN_HOST: 0.0.0.0
+ MINT_LISTEN_PORT: 3337
run: |
nohup poetry run mint &
- name: Run tests
diff --git a/cashu/core/crypto.py b/cashu/core/crypto.py
index a3e0500..e19f58a 100644
--- a/cashu/core/crypto.py
+++ b/cashu/core/crypto.py
@@ -3,7 +3,7 @@ import hashlib
from typing import Dict, List
from cashu.core.secp import PrivateKey, PublicKey
-from cashu.core.settings import MAX_ORDER
+from cashu.core.settings import settings
# entropy = bytes([random.getrandbits(8) for i in range(16)])
# mnemonic = bip39.mnemonic_from_bytes(entropy)
@@ -27,12 +27,14 @@ def derive_keys(master_key: str, derivation_path: str = ""):
.encode("utf-8")[:32],
raw=True,
)
- for i in range(MAX_ORDER)
+ for i in range(settings.max_order)
}
def derive_pubkeys(keys: Dict[int, PrivateKey]):
- return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]}
+ return {
+ amt: keys[amt].pubkey for amt in [2**i for i in range(settings.max_order)]
+ }
def derive_keyset_id(keys: Dict[int, PublicKey]):
diff --git a/cashu/core/helpers.py b/cashu/core/helpers.py
index 9b38c71..d8079cf 100644
--- a/cashu/core/helpers.py
+++ b/cashu/core/helpers.py
@@ -3,7 +3,7 @@ from functools import partial, wraps
from typing import List
from cashu.core.base import Proof
-from cashu.core.settings import LIGHTNING_FEE_PERCENT, LIGHTNING_RESERVE_FEE_MIN
+from cashu.core.settings import settings
def sum_proofs(proofs: List[Proof]):
@@ -39,5 +39,6 @@ def fee_reserve(amount_msat: int, internal=False) -> int:
if internal:
return 0
return max(
- int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0)
+ int(settings.lightning_reserve_fee_min),
+ int(amount_msat * settings.lightning_fee_percent / 100.0),
)
diff --git a/cashu/core/settings.py b/cashu/core/settings.py
index 523fa87..5b6a73a 100644
--- a/cashu/core/settings.py
+++ b/cashu/core/settings.py
@@ -1,72 +1,112 @@
import os
import sys
from pathlib import Path
-from typing import Union
+from typing import List, Union
from environs import Env # type: ignore
+from pydantic import BaseSettings, Extra, Field, validator
env = Env()
-# env file: default to current dir, else home dir
-ENV_FILE = os.path.join(os.getcwd(), ".env")
-if not os.path.isfile(ENV_FILE):
- ENV_FILE = os.path.join(str(Path.home()), ".cashu", ".env")
-if os.path.isfile(ENV_FILE):
- env.read_env(ENV_FILE)
-else:
- ENV_FILE = ""
- env.read_env(recurse=False)
-
-DEBUG = env.bool("DEBUG", default=False)
-if not DEBUG:
- sys.tracebacklimit = 0
-
-CASHU_DIR = env.str("CASHU_DIR", default=os.path.join(str(Path.home()), ".cashu"))
-CASHU_DIR = CASHU_DIR.replace("~", str(Path.home()))
-assert len(CASHU_DIR), "CASHU_DIR not defined"
-
-TOR = env.bool("TOR", default=True)
-
-SOCKS_HOST = env.str("SOCKS_HOST", default=None)
-SOCKS_PORT = env.int("SOCKS_PORT", default=9050)
-
-LIGHTNING = env.bool("LIGHTNING", default=True)
-LIGHTNING_FEE_PERCENT = env.float("LIGHTNING_FEE_PERCENT", default=1.0)
-assert LIGHTNING_FEE_PERCENT >= 0, "LIGHTNING_FEE_PERCENT must be at least 0"
-LIGHTNING_RESERVE_FEE_MIN = env.float("LIGHTNING_RESERVE_FEE_MIN", default=2000)
-
-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", default=None)
-MINT_HOST = env.str("MINT_HOST", default="8333.space")
-MINT_PORT = env.int("MINT_PORT", default=3338)
-
-MINT_LIGHTNING_BACKEND = env.str("MINT_LIGHTNING_BACKEND", default="FakeWallet")
-MINT_DATABASE = env.str("MINT_DATABASE", default="data/mint")
-
-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)
-
-NOSTR_PRIVATE_KEY = env.str("NOSTR_PRIVATE_KEY", default=None)
-NOSTR_RELAYS = env.list(
- "NOSTR_RELAYS",
- default=[
- "wss://nostr-pub.wellorder.net",
- "wss://relay.damus.io",
- "wss://nostr.zebedee.cloud",
- "wss://relay.snort.social",
- "wss://nostr.fmt.wiz.biz",
- ],
-)
-
-MAX_ORDER = 64
VERSION = "0.9.4"
+
+
+def find_env_file():
+ # env file: default to current dir, else home dir
+ ENV_FILE = os.path.join(os.getcwd(), ".env")
+ if not os.path.isfile(ENV_FILE):
+ ENV_FILE = os.path.join(str(Path.home()), ".cashu", ".env")
+ if os.path.isfile(ENV_FILE):
+ env.read_env(ENV_FILE)
+ else:
+ ENV_FILE = ""
+ return ENV_FILE
+
+
+class CashuSettings(BaseSettings):
+ env_file: str = Field(default=None)
+ lightning: bool = Field(default=True)
+ lightning_fee_percent: float = Field(default=1.0)
+ lightning_reserve_fee_min: int = Field(default=2000)
+ max_order: int = Field(default=64)
+
+ class Config:
+ env_file = find_env_file()
+ env_file_encoding = "utf-8"
+ case_sensitive = False
+ extra = Extra.ignore
+
+ # def __init__(self, env_file=None):
+ # self.env_file = env_file or self.env_file
+
+
+class EnvSettings(CashuSettings):
+ debug: bool = Field(default=False)
+ host: str = Field(default="127.0.0.1")
+ port: int = Field(default=5000)
+ cashu_dir: str = Field(default=os.path.join(str(Path.home()), ".cashu"))
+
+
+class MintSettings(CashuSettings):
+ mint_private_key: str = Field(default=None)
+ mint_listen_host: str = Field(default="127.0.0.1")
+ mint_listen_port: int = Field(default=3338)
+ mint_lightning_backend: str = Field(default="LNbitsWallet")
+ mint_database: str = Field(default="data/mint")
+
+ mint_lnbits_endpoint: str = Field(default=None)
+ mint_lnbits_key: str = Field(default=None)
+
+
+class WalletSettings(CashuSettings):
+ lightning: bool = Field(default=True)
+ tor: bool = Field(default=True)
+ socks_host: str = Field(default=None)
+ socks_port: int = Field(default=9050)
+ mint_url: str = Field(default=None)
+ mint_host: str = Field(default="8333.space")
+ mint_port: int = Field(default=3338)
+
+ nostr_private_key: str = Field(default=None)
+ nostr_relays: List[str] = Field(
+ default=[
+ "wss://nostr-pub.wellorder.net",
+ "wss://relay.damus.io",
+ "wss://nostr.zebedee.cloud",
+ "wss://relay.snort.social",
+ "wss://nostr.fmt.wiz.biz",
+ ]
+ )
+
+
+class Settings(EnvSettings, MintSettings, WalletSettings, CashuSettings):
+ version: str = Field(default=VERSION)
+
+ # def __init__(self, env_file=None):
+ # super().Config(env_file=env_file)
+
+
+settings = Settings()
+
+
+def startup_settings_tasks():
+ # set env_file (this does not affect the settings module, it's just for reading)
+ settings.env_file = find_env_file()
+
+ if not settings.debug:
+ # set traceback limit
+ sys.tracebacklimit = 0
+
+ # replace ~ with home directory in cashu_dir
+ settings.cashu_dir = settings.cashu_dir.replace("~", str(Path.home()))
+
+ # set mint_url if only mint_host is set
+ if not settings.mint_url:
+ if settings.mint_host in ["localhost", "127.0.0.1"] and settings.mint_port:
+ # localhost without https
+ settings.mint_url = f"http://{settings.mint_host}:{settings.mint_port}"
+ else:
+ settings.mint_url = f"https://{settings.mint_host}:{settings.mint_port}"
+
+
+startup_settings_tasks()
diff --git a/cashu/lightning/lnbits.py b/cashu/lightning/lnbits.py
index f7e2db3..a3125b6 100644
--- a/cashu/lightning/lnbits.py
+++ b/cashu/lightning/lnbits.py
@@ -3,7 +3,7 @@ from typing import Dict, Optional
import requests
-from cashu.core.settings import DEBUG, LNBITS_ENDPOINT, LNBITS_KEY
+from cashu.core.settings import settings
from .base import (
InvoiceResponse,
@@ -18,14 +18,14 @@ class LNbitsWallet(Wallet):
"""https://github.com/lnbits/lnbits"""
def __init__(self):
- self.endpoint = LNBITS_ENDPOINT
+ self.endpoint = settings.mint_lnbits_endpoint
- key = LNBITS_KEY
+ key = settings.mint_lnbits_key
self.key = {"X-Api-Key": key}
self.s = requests.Session()
self.s.auth = ("user", "pass")
self.s.headers.update({"X-Api-Key": key})
- self.s.verify = not DEBUG
+ self.s.verify = not settings.debug
async def status(self) -> StatusResponse:
try:
diff --git a/cashu/mint/app.py b/cashu/mint/app.py
index d4594cc..8cf1a3c 100644
--- a/cashu/mint/app.py
+++ b/cashu/mint/app.py
@@ -7,7 +7,7 @@ from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.cors import CORSMiddleware
-from cashu.core.settings import DEBUG, VERSION
+from cashu.core.settings import settings
from .router import router
from .startup import start_mint_init
@@ -33,7 +33,7 @@ def create_app(config_object="core.settings") -> FastAPI:
def __init__(self):
self.padding = 0
self.minimal_fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}\n"
- if DEBUG:
+ if settings.debug:
self.fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <4} | {name}:{function}:{line} | {message}\n"
else:
self.fmt: str = self.minimal_fmt
@@ -53,7 +53,7 @@ def create_app(config_object="core.settings") -> FastAPI:
logger.log(level, record.getMessage())
logger.remove()
- log_level: str = "DEBUG" if DEBUG else "INFO"
+ log_level: str = "DEBUG" if settings.debug else "INFO"
formatter = Formatter()
logger.add(sys.stderr, level=log_level, format=formatter.format)
@@ -82,7 +82,7 @@ def create_app(config_object="core.settings") -> FastAPI:
app = FastAPI(
title="Cashu Python Mint",
description="Ecash wallet and mint for Bitcoin",
- version=VERSION,
+ version=settings.version,
license_info={
"name": "MIT License",
"url": "https://raw.githubusercontent.com/cashubtc/cashu/main/LICENSE",
diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py
index 5d3d4cd..a170543 100644
--- a/cashu/mint/ledger.py
+++ b/cashu/mint/ledger.py
@@ -18,7 +18,7 @@ from cashu.core.db import Database
from cashu.core.helpers import fee_reserve, sum_proofs
from cashu.core.script import verify_script
from cashu.core.secp import PublicKey
-from cashu.core.settings import LIGHTNING, MAX_ORDER, VERSION
+from cashu.core.settings import settings
from cashu.core.split import amount_split
from cashu.lightning.base import Wallet
from cashu.mint.crud import LedgerCrud
@@ -51,7 +51,9 @@ class Ledger:
async def load_keyset(self, derivation_path, autosave=True):
"""Load current keyset keyset or generate new one."""
keyset = MintKeyset(
- seed=self.master_key, derivation_path=derivation_path, version=VERSION
+ seed=self.master_key,
+ derivation_path=derivation_path,
+ version=settings.version,
)
# check if current keyset is stored in db and store if not
logger.trace(f"Loading keyset {keyset.id} from db.")
@@ -192,7 +194,9 @@ class Ledger:
def _verify_amount(self, amount: int):
"""Any amount used should be a positive integer not larger than 2^MAX_ORDER."""
- valid = isinstance(amount, int) and amount > 0 and amount < 2**MAX_ORDER
+ valid = (
+ isinstance(amount, int) and amount > 0 and amount < 2**settings.max_order
+ )
if not valid:
raise Exception("invalid amount: " + str(amount))
return amount
@@ -359,7 +363,7 @@ class Ledger:
amounts = [b.amount for b in B_s]
amount = sum(amounts)
# check if lightning invoice was paid
- if LIGHTNING:
+ if settings.lightning:
if not payment_hash:
raise Exception("no payment_hash provided.")
try:
@@ -368,8 +372,10 @@ class Ledger:
raise e
for amount in amounts:
- if amount not in [2**i for i in range(MAX_ORDER)]:
- raise Exception(f"Can only mint amounts with 2^n up to {2**MAX_ORDER}.")
+ if amount not in [2**i for i in range(settings.max_order)]:
+ raise Exception(
+ f"Can only mint amounts with 2^n up to {2**settings.max_order}."
+ )
promises = await self._generate_promises(B_s, keyset)
return promises
@@ -391,7 +397,7 @@ class Ledger:
"provided proofs not enough for Lightning payment."
)
- if LIGHTNING:
+ if settings.lightning:
status, preimage = await self._pay_lightning_invoice(invoice, fees_msat)
else:
status, preimage = True, "preimage"
@@ -413,7 +419,7 @@ class Ledger:
"""Returns the fees (in msat) required to pay this pr."""
# hack: check if it's internal, if it exists, it will return paid = False,
# if id does not exist (not internal), it returns paid = None
- if LIGHTNING:
+ if settings.lightning:
decoded_invoice = bolt11.decode(pr)
amount = math.ceil(decoded_invoice.amount_msat / 1000)
paid = await self.lightning.get_invoice_status(decoded_invoice.payment_hash)
diff --git a/cashu/mint/main.py b/cashu/mint/main.py
index 47c86ae..bb04e5d 100644
--- a/cashu/mint/main.py
+++ b/cashu/mint/main.py
@@ -4,7 +4,7 @@ import click
import uvicorn
from click import Context
-from cashu.core.settings import MINT_SERVER_HOST, MINT_SERVER_PORT
+from cashu.core.settings import settings
@click.command(
@@ -13,15 +13,15 @@ from cashu.core.settings import MINT_SERVER_HOST, MINT_SERVER_PORT
allow_extra_args=True,
)
)
-@click.option("--port", default=MINT_SERVER_PORT, help="Port to listen on")
-@click.option("--host", default=MINT_SERVER_HOST, help="Host to run mint on")
+@click.option("--port", default=settings.mint_listen_port, help="Port to listen on")
+@click.option("--host", default=settings.mint_listen_host, help="Host to run mint on")
@click.option("--ssl-keyfile", default=None, help="Path to SSL keyfile")
@click.option("--ssl-certfile", default=None, help="Path to SSL certificate")
@click.pass_context
def main(
ctx: Context,
- port: int = MINT_SERVER_PORT,
- host: str = MINT_SERVER_HOST,
+ port: int = settings.mint_listen_port,
+ host: str = settings.mint_listen_host,
ssl_keyfile: Optional[str] = None,
ssl_certfile: Optional[str] = None,
):
diff --git a/cashu/mint/startup.py b/cashu/mint/startup.py
index 53f1ca7..632a305 100644
--- a/cashu/mint/startup.py
+++ b/cashu/mint/startup.py
@@ -7,26 +7,24 @@ from loguru import logger
from cashu.core.db import Database
from cashu.core.migrations import migrate_databases
-from cashu.core.settings import (
- CASHU_DIR,
- LIGHTNING,
- MINT_DATABASE,
- MINT_LIGHTNING_BACKEND,
- MINT_PRIVATE_KEY,
-)
+from cashu.core.settings import settings
from cashu.lightning.fake import FakeWallet # type: ignore
from cashu.lightning.lnbits import LNbitsWallet # type: ignore
from cashu.mint import migrations
from cashu.mint.ledger import Ledger
+logger.debug("Enviroment Settings:")
+for key, value in settings.dict().items():
+ logger.debug(f"{key}: {value}")
+
wallets_module = importlib.import_module("cashu.lightning")
-LIGHTNING_BACKEND = getattr(wallets_module, MINT_LIGHTNING_BACKEND)()
+lightning_backend = getattr(wallets_module, settings.mint_lightning_backend)()
ledger = Ledger(
- db=Database("mint", MINT_DATABASE),
- seed=MINT_PRIVATE_KEY,
+ db=Database("mint", settings.mint_database),
+ seed=settings.mint_private_key,
derivation_path="0/0/0/0",
- lightning=LIGHTNING_BACKEND,
+ lightning=lightning_backend,
)
@@ -36,8 +34,8 @@ async def start_mint_init():
await ledger.load_used_proofs()
await ledger.init_keysets()
- if LIGHTNING:
- logger.info(f"Using backend: {MINT_LIGHTNING_BACKEND}")
+ if settings.lightning:
+ logger.info(f"Using backend: {settings.mint_lightning_backend}")
error_message, balance = await ledger.lightning.status()
if error_message:
logger.warning(
@@ -46,5 +44,5 @@ async def start_mint_init():
)
logger.info(f"Lightning balance: {balance} msat")
- logger.info(f"Data dir: {CASHU_DIR}")
+ logger.info(f"Data dir: {settings.cashu_dir}")
logger.info("Mint started.")
diff --git a/cashu/wallet/__init__.py b/cashu/wallet/__init__.py
index 3a33a17..df2a29f 100644
--- a/cashu/wallet/__init__.py
+++ b/cashu/wallet/__init__.py
@@ -4,8 +4,8 @@ sys.tracebacklimit = None # type: ignore
from loguru import logger
-from cashu.core.settings import DEBUG
+from cashu.core.settings import settings
# configure logger
logger.remove()
-logger.add(sys.stderr, level="DEBUG" if DEBUG else "INFO")
+logger.add(sys.stderr, level="DEBUG" if settings.debug else "INFO")
diff --git a/cashu/wallet/cli/cli.py b/cashu/wallet/cli/cli.py
index 07b4b6e..fb493da 100644
--- a/cashu/wallet/cli/cli.py
+++ b/cashu/wallet/cli/cli.py
@@ -21,19 +21,7 @@ from loguru import logger
from cashu.core.base import Proof, TokenV2
from cashu.core.helpers import sum_proofs
from cashu.core.migrations import migrate_databases
-from cashu.core.settings import (
- CASHU_DIR,
- DEBUG,
- ENV_FILE,
- LIGHTNING,
- MINT_URL,
- NOSTR_PRIVATE_KEY,
- NOSTR_RELAYS,
- SOCKS_HOST,
- SOCKS_PORT,
- TOR,
- VERSION,
-)
+from cashu.core.settings import settings
from cashu.nostr.nostr.client.client import NostrClient
from cashu.tor.tor import TorProxy
from cashu.wallet import migrations
@@ -69,7 +57,12 @@ class NaturalOrderGroup(click.Group):
@click.group(cls=NaturalOrderGroup)
-@click.option("--host", "-h", default=MINT_URL, help=f"Mint URL (default: {MINT_URL}).")
+@click.option(
+ "--host",
+ "-h",
+ default=settings.mint_url,
+ help=f"Mint URL (default: {settings.mint_url}).",
+)
@click.option(
"--wallet",
"-w",
@@ -79,24 +72,22 @@ class NaturalOrderGroup(click.Group):
)
@click.pass_context
def cli(ctx: Context, host: str, walletname: str):
- if TOR and not TorProxy().check_platform():
+ if settings.tor and not TorProxy().check_platform():
error_str = "Your settings say TOR=true but the built-in Tor bundle is not supported on your system. You have two options: Either install Tor manually and set TOR=FALSE and SOCKS_HOST=localhost and SOCKS_PORT=9050 in your Cashu config (recommended). Or turn off Tor by setting TOR=false (not recommended). Cashu will not work until you edit your config file accordingly."
error_str += "\n\n"
- if ENV_FILE:
- error_str += f"Edit your Cashu config file here: {ENV_FILE}"
- env_path = ENV_FILE
+ if settings.env_file:
+ error_str += f"Edit your Cashu config file here: {settings.env_file}"
+ env_path = settings.env_file
else:
- error_str += (
- f"Ceate a new Cashu config file here: {os.path.join(CASHU_DIR, '.env')}"
- )
- env_path = os.path.join(CASHU_DIR, ".env")
+ error_str += f"Ceate a new Cashu config file here: {os.path.join(settings.cashu_dir, '.env')}"
+ env_path = os.path.join(settings.cashu_dir, ".env")
error_str += f'\n\nYou can turn off Tor with this command: echo "TOR=FALSE" >> {env_path}'
raise Exception(error_str)
ctx.ensure_object(dict)
ctx.obj["HOST"] = host
ctx.obj["WALLET_NAME"] = walletname
- wallet = Wallet(ctx.obj["HOST"], os.path.join(CASHU_DIR, walletname))
+ wallet = Wallet(ctx.obj["HOST"], os.path.join(settings.cashu_dir, walletname))
ctx.obj["WALLET"] = wallet
asyncio.run(init_wallet(wallet))
pass
@@ -149,7 +140,7 @@ async def invoice(ctx: Context, amount: int, hash: str):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
wallet.status()
- if not LIGHTNING:
+ if not settings.lightning:
r = await wallet.mint(amount)
elif amount and not hash:
invoice = await wallet.request_mint(amount)
@@ -601,13 +592,15 @@ async def invoices(ctx):
@coro
async def wallets(ctx):
# list all directories
- wallets = [d for d in listdir(CASHU_DIR) if isdir(join(CASHU_DIR, d))]
+ wallets = [
+ d for d in listdir(settings.cashu_dir) if isdir(join(settings.cashu_dir, d))
+ ]
try:
wallets.remove("mint")
except ValueError:
pass
for w in wallets:
- wallet = Wallet(ctx.obj["HOST"], os.path.join(CASHU_DIR, w))
+ wallet = Wallet(ctx.obj["HOST"], os.path.join(settings.cashu_dir, w))
try:
await init_wallet(wallet)
if wallet.proofs and len(wallet.proofs):
@@ -625,20 +618,20 @@ async def wallets(ctx):
@click.pass_context
@coro
async def info(ctx: Context):
- print(f"Version: {VERSION}")
+ print(f"Version: {settings.version}")
print(f"Wallet: {ctx.obj['WALLET_NAME']}")
- if DEBUG:
- print(f"Debug: {DEBUG}")
- print(f"Cashu dir: {CASHU_DIR}")
- if ENV_FILE:
- print(f"Settings: {ENV_FILE}")
- if TOR:
- print(f"Tor enabled: {TOR}")
- if NOSTR_PRIVATE_KEY:
- client = NostrClient(private_key=NOSTR_PRIVATE_KEY, connect=False)
+ if settings.debug:
+ print(f"Debug: {settings.debug}")
+ print(f"Cashu dir: {settings.cashu_dir}")
+ if settings.env_file:
+ print(f"Settings: {settings.env_file}")
+ if settings.tor:
+ print(f"Tor enabled: {settings.tor}")
+ if settings.nostr_private_key:
+ client = NostrClient(private_key=settings.nostr_private_key, connect=False)
print(f"Nostr public key: {client.public_key.bech32()}")
- print(f"Nostr relays: {NOSTR_RELAYS}")
- if SOCKS_HOST:
- print(f"Socks proxy: {SOCKS_HOST}:{SOCKS_PORT}")
+ print(f"Nostr relays: {settings.nostr_relays}")
+ if settings.socks_host:
+ print(f"Socks proxy: {settings.socks_host}:{settings.socks_port}")
print(f"Mint URL: {ctx.obj['HOST']}")
return
diff --git a/cashu/wallet/cli/cli_helpers.py b/cashu/wallet/cli/cli_helpers.py
index 3f53c23..2d884b3 100644
--- a/cashu/wallet/cli/cli_helpers.py
+++ b/cashu/wallet/cli/cli_helpers.py
@@ -8,7 +8,7 @@ from loguru import logger
from cashu.core.base import Proof, TokenV2, TokenV2Mint, WalletKeyset
from cashu.core.helpers import sum_proofs
-from cashu.core.settings import CASHU_DIR, MINT_URL, NOSTR_PRIVATE_KEY, NOSTR_RELAYS
+from cashu.core.settings import settings
from cashu.wallet.crud import get_keyset
from cashu.wallet.wallet import Wallet as Wallet
@@ -32,7 +32,7 @@ async def verify_mints(ctx: Context, token: TokenV2):
for keyset in set([id for id in mint.ids if id in proofs_keysets]):
# init a temporary wallet object
keyset_wallet = Wallet(
- mint.url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"])
+ mint.url, os.path.join(settings.cashu_dir, ctx.obj["WALLET_NAME"])
)
# make sure that this mint supports this keyset
mint_keysets = await keyset_wallet._get_keyset_ids(mint.url)
@@ -81,7 +81,7 @@ async def redeem_multimint(ctx: Context, token: TokenV2, script, signature):
logger.debug(f"Redeeming tokens from keyset {keyset}")
# init a temporary wallet object
keyset_wallet = Wallet(
- mint.url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"])
+ mint.url, os.path.join(settings.cashu_dir, ctx.obj["WALLET_NAME"])
)
# load the keys
@@ -147,7 +147,9 @@ async def get_mint_wallet(ctx: Context):
mint_url = list(mint_balances.keys())[mint_nr - 1]
# load this mint_url into a wallet
- mint_wallet = Wallet(mint_url, os.path.join(CASHU_DIR, ctx.obj["WALLET_NAME"]))
+ mint_wallet = Wallet(
+ mint_url, os.path.join(settings.cashu_dir, ctx.obj["WALLET_NAME"])
+ )
mint_keysets: WalletKeyset = await get_keyset(mint_url=mint_url, db=mint_wallet.db) # type: ignore
# load the keys
@@ -196,7 +198,8 @@ async def proofs_to_serialized_tokenv2(wallet, proofs: List[Proof], url: str):
url = ks.mint_url if ks and ks.mint_url else ""
url = url or (
- input(f"Enter mint URL (press enter for default {MINT_URL}): ") or MINT_URL
+ input(f"Enter mint URL (press enter for default {settings.mint_url}): ")
+ or settings.mint_url
)
token.mints.append(TokenV2Mint(url=url, ids=keysets))
diff --git a/cashu/wallet/cli/nostr.py b/cashu/wallet/cli/nostr.py
index 95916cf..f4d449e 100644
--- a/cashu/wallet/cli/nostr.py
+++ b/cashu/wallet/cli/nostr.py
@@ -6,7 +6,7 @@ import click
from click import Context
from requests.exceptions import ConnectionError
-from cashu.core.settings import NOSTR_PRIVATE_KEY, NOSTR_RELAYS
+from cashu.core.settings import settings
from cashu.nostr.nostr.client.client import NostrClient
from cashu.nostr.nostr.event import Event
from cashu.nostr.nostr.key import PublicKey
@@ -79,8 +79,10 @@ async def send_nostr(ctx: Context, amount: int, pubkey: str, verbose: bool, yes:
default=True,
)
- client = NostrClient(private_key=NOSTR_PRIVATE_KEY or "", relays=NOSTR_RELAYS)
- if verbose and not NOSTR_PRIVATE_KEY:
+ client = NostrClient(
+ private_key=settings.nostr_private_key or "", relays=settings.nostr_relays
+ )
+ if verbose and not settings.nostr_private_key:
# we generated a random key if none was present
print(f"Your nostr private key: {client.private_key.bech32()}")
@@ -91,12 +93,14 @@ async def send_nostr(ctx: Context, amount: int, pubkey: str, verbose: bool, yes:
async def receive_nostr(ctx: Context, verbose: bool):
- if NOSTR_PRIVATE_KEY is None:
+ if settings.nostr_private_key is None:
print(
"Warning: No nostr private key set! You don't have NOSTR_PRIVATE_KEY set in your .env file. I will create a random private key for this session but I will not remember it."
)
print("")
- client = NostrClient(private_key=NOSTR_PRIVATE_KEY, relays=NOSTR_RELAYS)
+ client = NostrClient(
+ private_key=settings.nostr_private_key, relays=settings.nostr_relays
+ )
print(f"Your nostr public key: {client.public_key.bech32()}")
if verbose:
print(f"Your nostr private key (do not share!): {client.private_key.bech32()}")
diff --git a/cashu/wallet/wallet.py b/cashu/wallet/wallet.py
index bedb19d..4ed201c 100644
--- a/cashu/wallet/wallet.py
+++ b/cashu/wallet/wallet.py
@@ -42,7 +42,7 @@ from cashu.core.script import (
step2_carol_sign_tx,
)
from cashu.core.secp import PublicKey
-from cashu.core.settings import DEBUG, MAX_ORDER, SOCKS_HOST, SOCKS_PORT, TOR, VERSION
+from cashu.core.settings import settings
from cashu.core.split import amount_split
from cashu.tor.tor import TorProxy
from cashu.wallet.crud import (
@@ -67,16 +67,16 @@ def async_set_requests(func):
"""
async def wrapper(self, *args, **kwargs):
- self.s.headers.update({"Client-version": VERSION})
- if DEBUG:
+ self.s.headers.update({"Client-version": settings.version})
+ if settings.debug:
self.s.verify = False
socks_host, socks_port = None, None
- if TOR and TorProxy().check_platform():
+ if settings.tor and TorProxy().check_platform():
self.tor = TorProxy(timeout=True)
self.tor.run_daemon(verbose=True)
socks_host, socks_port = "localhost", 9050
else:
- socks_host, socks_port = SOCKS_HOST, SOCKS_PORT
+ socks_host, socks_port = settings.socks_host, settings.socks_port
if socks_host and socks_port:
proxies = {
@@ -515,8 +515,10 @@ class Wallet(LedgerAPI):
List[Proof]: Newly minted proofs.
"""
for amount in amounts:
- if amount not in [2**i for i in range(MAX_ORDER)]:
- raise Exception(f"Can only mint amounts with 2^n up to {2**MAX_ORDER}.")
+ if amount not in [2**i for i in range(settings.max_order)]:
+ raise Exception(
+ f"Can only mint amounts with 2^n up to {2**settings.max_order}."
+ )
proofs = await super().mint(amounts, payment_hash)
if proofs == []:
raise Exception("received no proofs.")
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 79eb5d8..7c1b63f 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -4,7 +4,7 @@ import pytest
from click.testing import CliRunner
from cashu.core.migrations import migrate_databases
-from cashu.core.settings import VERSION
+from cashu.core.settings import settings
from cashu.wallet import migrations
from cashu.wallet.cli.cli import cli
from cashu.wallet.wallet import Wallet
@@ -29,7 +29,7 @@ def test_info():
)
print("INFO")
print(result.output)
- result.output.startswith(f"Version: {VERSION}")
+ result.output.startswith(f"Version: {settings.version}")
assert result.exit_code == 0
diff --git a/tests/test_mint.py b/tests/test_mint.py
index f175ce6..e50e6be 100644
--- a/tests/test_mint.py
+++ b/tests/test_mint.py
@@ -11,7 +11,7 @@ SERVER_ENDPOINT = "http://localhost:3338"
import os
from cashu.core.db import Database
-from cashu.core.settings import MAX_ORDER
+from cashu.core.settings import settings
from cashu.mint import migrations
from cashu.mint.ledger import Ledger
@@ -63,7 +63,7 @@ async def test_keysets(ledger: Ledger):
async def test_get_keyset(ledger: Ledger):
keyset = ledger.get_keyset()
assert type(keyset) == dict
- assert len(keyset) == MAX_ORDER
+ assert len(keyset) == settings.max_order
@pytest.mark.asyncio
diff --git a/tests/test_wallet.py b/tests/test_wallet.py
index ea25596..b9e6d6b 100644
--- a/tests/test_wallet.py
+++ b/tests/test_wallet.py
@@ -7,7 +7,7 @@ import pytest_asyncio
from cashu.core.base import Proof
from cashu.core.helpers import async_unwrap, sum_proofs
from cashu.core.migrations import migrate_databases
-from cashu.core.settings import MAX_ORDER
+from cashu.core.settings import settings
from cashu.wallet import migrations
from cashu.wallet.wallet import Wallet
from cashu.wallet.wallet import Wallet as Wallet1
@@ -51,7 +51,7 @@ async def wallet2(mint):
@pytest.mark.asyncio
async def test_get_keys(wallet1: Wallet):
assert wallet1.keys.public_keys
- assert len(wallet1.keys.public_keys) == MAX_ORDER
+ assert len(wallet1.keys.public_keys) == settings.max_order
keyset = await wallet1._get_keys(wallet1.url)
assert keyset.id is not None
assert type(keyset.id) == str
@@ -61,7 +61,7 @@ async def test_get_keys(wallet1: Wallet):
@pytest.mark.asyncio
async def test_get_keyset(wallet1: Wallet):
assert wallet1.keys.public_keys
- assert len(wallet1.keys.public_keys) == MAX_ORDER
+ assert len(wallet1.keys.public_keys) == settings.max_order
# let's get the keys first so we can get a keyset ID that we use later
keys1 = await wallet1._get_keys(wallet1.url)
# gets the keys of a specific keyset
@@ -107,7 +107,7 @@ async def test_mint_amounts_wrong_order(wallet1: Wallet):
"""Mint amount that is not part in 2^n"""
await assert_err(
wallet1.mint_amounts([1, 2, 3]),
- f"Can only mint amounts with 2^n up to {2**MAX_ORDER}.",
+ f"Can only mint amounts with 2^n up to {2**settings.max_order}.",
)