feat: ship fresh nodes with default trusted Cashu mints

cashu_mints previously defaulted to an empty list, leaving a new node in a
half-working state: it silently trusted the hardcoded minibits primary mint
but advertised no mints in /v1/info or its NIP-91 listing, so clients
discovering the node had no way to know where to pay.

- default cashu_mints to minibits + cubabitcoin via shared DEFAULT_CASHU_MINTS
- reuse the constant for the primary_mint fallback (removes duplicate literal)
- CASHU_MINTS env or dashboard edits still replace the list entirely; an
  explicitly empty value keeps only the primary mint trusted
- document the defaults in configuration.md, dashboard.md, .env.example

Existing nodes are unaffected: the settings-blob merge skips persisted empty
lists, so unconfigured nodes pick up the defaults on restart while nodes with
explicit mints keep theirs.
This commit is contained in:
redshift
2026-09-21 16:51:33 +03:00
parent f5add71b0b
commit e2f6e37ebe
4 changed files with 29 additions and 4 deletions
+1
View File
@@ -45,6 +45,7 @@ ROUTSTR_SECRET_KEY=
# ONION_URL=http://mynode.onion (auto fetched from compose) # ONION_URL=http://mynode.onion (auto fetched from compose)
# RELAYS="wss://relay.damus.io,wss://relay.nostr.band,wss://eden.nostr.land,wss://relay.routstr.com" # RELAYS="wss://relay.damus.io,wss://relay.nostr.band,wss://eden.nostr.land,wss://relay.routstr.com"
# ENABLE_ANALYTICS_SHARING=true # ENABLE_ANALYTICS_SHARING=true
# CASHU_MINTS="https://mint.minibits.cash/Bitcoin,https://mint.cubabitcoin.org" # this is the default
# CASHU_MINTS="https://mint.minibits.cash/Bitcoin,https://mint.cubabitcoin.org,https://ecashmint.otrta.me" # CASHU_MINTS="https://mint.minibits.cash/Bitcoin,https://mint.cubabitcoin.org,https://ecashmint.otrta.me"
# MINT_OPERATION_CONCURRENCY=4 # MINT_OPERATION_CONCURRENCY=4
# MINT_OPERATION_TIMEOUT_SECONDS=30 # MINT_OPERATION_TIMEOUT_SECONDS=30
+10 -1
View File
@@ -139,6 +139,15 @@ Which mints to accept payments from:
| --------- | ------------------------------- | | --------- | ------------------------------- |
| **Mints** | List of trusted Cashu mint URLs | | **Mints** | List of trusted Cashu mint URLs |
A fresh node ships with two mints preconfigured:
- `https://mint.minibits.cash/Bitcoin`
- `https://mint.cubabitcoin.org`
Setting `CASHU_MINTS` (env) or editing the list in the dashboard replaces this
default entirely. An explicitly empty value leaves only the primary mint
trusted.
### Lightning Withdrawals ### Lightning Withdrawals
Automatic profit withdrawal: Automatic profit withdrawal:
@@ -197,7 +206,7 @@ Use environment variables for:
| `NPUB` | Nostr public key (bech32) | — | | `NPUB` | Nostr public key (bech32) | — |
| `NSEC` | Legacy seed for the Nostr private key (otherwise set from the admin UI) | — | | `NSEC` | Legacy seed for the Nostr private key (otherwise set from the admin UI) | — |
| `ENABLE_ANALYTICS_SHARING` | Enable usage analytics sharing to Nostr | `true` | | `ENABLE_ANALYTICS_SHARING` | Enable usage analytics sharing to Nostr | `true` |
| `CASHU_MINTS` | Comma-separated mint URLs | `https://mint.minibits.cash/Bitcoin` | | `CASHU_MINTS` | Comma-separated mint URLs | `https://mint.minibits.cash/Bitcoin,https://mint.cubabitcoin.org` |
| `MINT_OPERATION_CONCURRENCY` | Concurrent mint/unit balance reads | `4` | | `MINT_OPERATION_CONCURRENCY` | Concurrent mint/unit balance reads | `4` |
| `MINT_OPERATION_TIMEOUT_SECONDS` | Per-attempt timeout for mint network calls | `30` | | `MINT_OPERATION_TIMEOUT_SECONDS` | Per-attempt timeout for mint network calls | `30` |
| `MINT_MAX_CONCURRENCY` | Concurrent operations allowed per mint (`0` disables the limit) | `4` | | `MINT_MAX_CONCURRENCY` | Concurrent operations allowed per mint (`0` disables the limit) | `4` |
+3 -1
View File
@@ -132,7 +132,9 @@ Connect to your AI provider:
### Cashu Mints ### Cashu Mints
Manage which mints you accept payments from: Manage which mints you accept payments from. A fresh node comes with two
default mints preconfigured (`https://mint.minibits.cash/Bitcoin` and
`https://mint.cubabitcoin.org`):
- **Add Mint** — Enter a mint URL - **Add Mint** — Enter a mint URL
- **Remove Mint** — Stop accepting from a mint - **Remove Mint** — Stop accepting from a mint
+15 -2
View File
@@ -11,6 +11,14 @@ from typing import Any
from pydantic.v1 import BaseModel, BaseSettings, Field from pydantic.v1 import BaseModel, BaseSettings, Field
from sqlmodel.ext.asyncio.session import AsyncSession from sqlmodel.ext.asyncio.session import AsyncSession
# Mints a fresh node trusts out of the box, shared by the settings default and
# the primary-mint fallback. Defined before the Settings class because the
# default_factory lambda resolves it at class-definition time.
DEFAULT_CASHU_MINTS: list[str] = [
"https://mint.minibits.cash/Bitcoin",
"https://mint.cubabitcoin.org",
]
class Settings(BaseSettings): class Settings(BaseSettings):
class Config: class Config:
@@ -37,7 +45,12 @@ class Settings(BaseSettings):
onion_url: str = Field(default="", env="ONION_URL") onion_url: str = Field(default="", env="ONION_URL")
# Cashu # Cashu
cashu_mints: list[str] = Field(default_factory=list, env="CASHU_MINTS") # Mints a fresh node trusts out of the box. Setting CASHU_MINTS (env or
# dashboard) replaces this list entirely; an explicitly empty value yields
# an empty list (no trusted mints beyond primary_mint).
cashu_mints: list[str] = Field(
default_factory=lambda: list(DEFAULT_CASHU_MINTS), env="CASHU_MINTS"
)
receive_ln_address: str = Field(default="", env="RECEIVE_LN_ADDRESS") receive_ln_address: str = Field(default="", env="RECEIVE_LN_ADDRESS")
primary_mint: str = Field(default="", env="PRIMARY_MINT_URL") primary_mint: str = Field(default="", env="PRIMARY_MINT_URL")
primary_mint_unit: str = Field(default="sat", env="PRIMARY_MINT_UNIT") primary_mint_unit: str = Field(default="sat", env="PRIMARY_MINT_UNIT")
@@ -256,7 +269,7 @@ def _apply_to_live_settings(data: dict[str, Any]) -> None:
def _compute_primary_mint(cashu_mints: list[str]) -> str: def _compute_primary_mint(cashu_mints: list[str]) -> str:
return cashu_mints[0] if cashu_mints else "https://mint.minibits.cash/Bitcoin" return cashu_mints[0] if cashu_mints else DEFAULT_CASHU_MINTS[0]
def derive_npub_from_nsec(nsec: str) -> str | None: def derive_npub_from_nsec(nsec: str) -> str | None: