Mint: Fakewallet support for USD (#488)

* fakewallet usd wip

* FakeWallet support for USD

* fix api return for receive

* use MINT_BACKEND_BOLT11_SAT everywhere
This commit is contained in:
callebtc
2024-03-22 12:11:40 +01:00
committed by GitHub
parent f4621345f3
commit 3ba1e81fcb
21 changed files with 168 additions and 93 deletions

View File

@@ -55,9 +55,9 @@ MINT_DERIVATION_PATH="m/0'/0'/0'"
MINT_DATABASE=data/mint
# Lightning
# Funding source backends
# Supported: FakeWallet, LndRestWallet, CoreLightningRestWallet, BlinkWallet, LNbitsWallet, StrikeUSDWallet
MINT_LIGHTNING_BACKEND=FakeWallet
MINT_BACKEND_BOLT11_SAT=FakeWallet
# for use with LNbitsWallet
MINT_LNBITS_ENDPOINT=https://legend.lnbits.com

View File

@@ -49,7 +49,7 @@ jobs:
poetry-version: ${{ inputs.poetry-version }}
- name: Run tests
env:
MINT_LIGHTNING_BACKEND: FakeWallet
MINT_BACKEND_BOLT11_SAT: FakeWallet
WALLET_NAME: test_wallet
MINT_HOST: localhost
MINT_PORT: 3337

View File

@@ -30,7 +30,7 @@ test:
test-lndrest:
PYTHONUNBUFFERED=1 \
DEBUG=true \
MINT_LIGHTNING_BACKEND=LndRestWallet \
MINT_BACKEND_BOLT11_SAT=LndRestWallet \
MINT_LND_REST_ENDPOINT=https://localhost:8081/ \
MINT_LND_REST_CERT=../cashu-regtest-enviroment/data/lnd-3/tls.cert \
MINT_LND_REST_MACAROON=../cashu-regtest-enviroment/data/lnd-3/data/chain/bitcoin/regtest/admin.macaroon \

View File

@@ -7,7 +7,7 @@
*Disclaimer: The author is NOT a cryptographer and this work has not been reviewed. This means that there is very likely a fatal flaw somewhere. Cashu is still experimental and not production-ready.*
Cashu is an Ecash implementation based on David Wagner's variant of Chaumian blinding ([protocol specs](https://github.com/cashubtc/nuts)). Token logic based on [minicash](https://github.com/phyro/minicash) ([description](https://gist.github.com/phyro/935badc682057f418842c72961cf096c)) which implements a [Blind Diffie-Hellman Key Exchange](https://cypherpunks.venona.com/date/1996/03/msg01848.html) scheme written down [here](https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406). The database mechanics in Cashu Nutshell and the Lightning backend uses parts from [LNbits](https://github.com/lnbits/lnbits-legend).
Cashu is an Ecash implementation based on David Wagner's variant of Chaumian blinding ([protocol specs](https://github.com/cashubtc/nuts)). Token logic based on [minicash](https://github.com/phyro/minicash) ([description](https://gist.github.com/phyro/935badc682057f418842c72961cf096c)) which implements a [Blind Diffie-Hellman Key Exchange](https://cypherpunks.venona.com/date/1996/03/msg01848.html) scheme written down [here](https://gist.github.com/RubenSomsen/be7a4760dd4596d06963d67baf140406).
<p align="center">
<a href="#the-cashu-protocol">Cashu protocol</a> ·
@@ -169,12 +169,19 @@ You can find the API docs at [http://localhost:4448/docs](http://localhost:4448/
# Running a mint
This command runs the mint on your local computer. Skip this step if you want to use the [public test mint](#test-instance) instead.
Before you can run your own mint, make sure to enable a Lightning backend in `MINT_LIGHTNING_BACKEND` and set `MINT_PRIVATE_KEY` in your `.env` file.
## Docker
```
docker run -d -p 3338:3338 --name nutshell -e MINT_BACKEND_BOLT11_SAT=FakeWallet -e MINT_LISTEN_HOST=0.0.0.0 -e MINT_LISTEN_PORT=3338 -e MINT_PRIVATE_KEY=TEST_PRIVATE_KEY cashubtc/nutshell:0.15.2 poetry run mint
```
## From this repository
Before you can run your own mint, make sure to enable a Lightning backend in `MINT_BACKEND_BOLT11_SAT` and set `MINT_PRIVATE_KEY` in your `.env` file.
```bash
poetry run mint
```
For testing, you can use Nutshell without a Lightning backend by setting `MINT_LIGHTNING_BACKEND=FakeWallet` in the `.env` file.
For testing, you can use Nutshell without a Lightning backend by setting `MINT_BACKEND_BOLT11_SAT=FakeWallet` in the `.env` file.
# Running tests
@@ -185,7 +192,7 @@ poetry install --with dev
Then, make sure to set up your mint's `.env` file to use a fake Lightning backend and disable Tor:
```bash
MINT_LIGHTNING_BACKEND=FakeWallet
MINT_BACKEND_BOLT11_SAT=FakeWallet
TOR=FALSE
```
You can run the tests with

View File

@@ -55,7 +55,11 @@ class MintSettings(CashuSettings):
mint_derivation_path_list: List[str] = Field(default=[])
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_lightning_backend: str = Field(default="") # deprecated
mint_backend_bolt11_sat: str = Field(default="")
mint_backend_bolt11_usd: str = Field(default="")
mint_database: str = Field(default="data/mint")
mint_test_database: str = Field(default="test_data/test_mint")
mint_peg_out_only: bool = Field(
@@ -204,5 +208,9 @@ def startup_settings_tasks():
if settings.socks_host and settings.socks_port:
settings.socks_proxy = f"socks5://{settings.socks_host}:{settings.socks_port}"
# backwards compatibility: set mint_backend_bolt11_sat from mint_lightning_backend
if settings.mint_lightning_backend:
settings.mint_backend_bolt11_sat = settings.mint_lightning_backend
startup_settings_tasks()

View File

@@ -7,5 +7,5 @@ from .lnbits import LNbitsWallet # noqa: F401
from .lndrest import LndRestWallet # noqa: F401
from .strike import StrikeUSDWallet # noqa: F401
if settings.mint_lightning_backend is None:
raise Exception("MINT_LIGHTNING_BACKEND not configured")
if settings.mint_backend_bolt11_sat is None or settings.mint_backend_bolt11_usd is None:
raise Exception("MINT_BACKEND_BOLT11_SAT or MINT_BACKEND_BOLT11_USD not set")

View File

@@ -62,12 +62,17 @@ class PaymentStatus(BaseModel):
class LightningBackend(ABC):
units: set[Unit]
supported_units: set[Unit]
unit: Unit
def assert_unit_supported(self, unit: Unit):
if unit not in self.units:
if unit not in self.supported_units:
raise Unsupported(f"Unit {unit} is not supported")
@abstractmethod
def __init__(self, unit: Unit, **kwargs):
pass
@abstractmethod
def status(self) -> Coroutine[None, None, StatusResponse]:
pass

View File

@@ -36,7 +36,6 @@ class BlinkWallet(LightningBackend):
Create API Key at: https://dashboard.blink.sv/
"""
units = set([Unit.sat, Unit.usd])
wallet_ids: Dict[Unit, str] = {}
endpoint = "https://api.blink.sv/graphql"
invoice_statuses = {"PENDING": None, "PAID": True, "EXPIRED": False}
@@ -47,7 +46,12 @@ class BlinkWallet(LightningBackend):
}
payment_statuses = {"SUCCESS": True, "PENDING": None, "FAILURE": False}
def __init__(self):
supported_units = set([Unit.sat, Unit.msat])
unit = Unit.sat
def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
assert settings.mint_blink_key, "MINT_BLINK_KEY not set"
self.client = httpx.AsyncClient(
verify=not settings.debug,
@@ -297,7 +301,7 @@ class BlinkWallet(LightningBackend):
... on SettlementViaLn {
preImage
}
}
}
}
}
}

View File

@@ -26,9 +26,12 @@ from .macaroon import load_macaroon
class CoreLightningRestWallet(LightningBackend):
units = set([Unit.sat, Unit.msat])
supported_units = set([Unit.sat, Unit.msat])
unit = Unit.sat
def __init__(self):
def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
macaroon = settings.mint_corelightning_rest_macaroon
assert macaroon, "missing cln-rest macaroon"

View File

@@ -1,5 +1,6 @@
import asyncio
import hashlib
import math
import random
from datetime import datetime
from os import urandom
@@ -28,7 +29,7 @@ from .base import (
class FakeWallet(LightningBackend):
units = set([Unit.sat, Unit.msat])
fake_btc_price = 1e8 / 1337
queue: asyncio.Queue[Bolt11] = asyncio.Queue(0)
payment_secrets: Dict[str, str] = dict()
paid_invoices: Set[str] = set()
@@ -41,6 +42,13 @@ class FakeWallet(LightningBackend):
32,
).hex()
supported_units = set([Unit.sat, Unit.msat, Unit.usd])
unit = Unit.sat
def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
async def status(self) -> StatusResponse:
return StatusResponse(error_message=None, balance=1337)
@@ -80,9 +88,19 @@ class FakeWallet(LightningBackend):
self.payment_secrets[payment_hash] = secret
amount_msat = 0
if self.unit == Unit.sat:
amount_msat = MilliSatoshi(amount.to(Unit.msat, round="up").amount)
elif self.unit == Unit.usd:
amount_msat = MilliSatoshi(
math.ceil(amount.amount / self.fake_btc_price * 1e9)
)
else:
raise NotImplementedError()
bolt11 = Bolt11(
currency="bc",
amount_msat=MilliSatoshi(amount.to(Unit.msat, round="up").amount),
amount_msat=amount_msat,
date=int(datetime.now().timestamp()),
tags=tags,
)
@@ -137,10 +155,19 @@ class FakeWallet(LightningBackend):
async def get_payment_quote(self, bolt11: str) -> PaymentQuoteResponse:
invoice_obj = decode(bolt11)
assert invoice_obj.amount_msat, "invoice has no amount."
amount_msat = int(invoice_obj.amount_msat)
fees_msat = fee_reserve(amount_msat)
fees = Amount(unit=Unit.msat, amount=fees_msat)
amount = Amount(unit=Unit.msat, amount=amount_msat)
if self.unit == Unit.sat:
amount_msat = int(invoice_obj.amount_msat)
fees_msat = fee_reserve(amount_msat)
fees = Amount(unit=Unit.msat, amount=fees_msat)
amount = Amount(unit=Unit.msat, amount=amount_msat)
elif self.unit == Unit.usd:
amount_usd = math.ceil(invoice_obj.amount_msat / 1e9 * self.fake_btc_price)
amount = Amount(unit=Unit.usd, amount=amount_usd)
fees = Amount(unit=Unit.usd, amount=1)
else:
raise NotImplementedError()
return PaymentQuoteResponse(
checking_id=invoice_obj.payment_hash, fee=fees, amount=amount
)

View File

@@ -22,9 +22,12 @@ from .base import (
class LNbitsWallet(LightningBackend):
"""https://github.com/lnbits/lnbits"""
units = set([Unit.sat])
supported_units = set([Unit.sat])
unit = Unit.sat
def __init__(self):
def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
self.endpoint = settings.mint_lnbits_endpoint
self.client = httpx.AsyncClient(
verify=not settings.debug,

View File

@@ -27,9 +27,12 @@ from .macaroon import load_macaroon
class LndRestWallet(LightningBackend):
"""https://api.lightning.community/rest/index.html#lnd-rest-api-reference"""
units = set([Unit.sat, Unit.msat])
supported_units = set([Unit.sat, Unit.msat])
unit = Unit.sat
def __init__(self):
def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
endpoint = settings.mint_lnd_rest_endpoint
cert = settings.mint_lnd_rest_cert

View File

@@ -19,9 +19,11 @@ from .base import (
class StrikeUSDWallet(LightningBackend):
"""https://github.com/lnbits/lnbits"""
units = [Unit.usd]
supported_units = [Unit.usd]
def __init__(self):
def __init__(self, unit: Unit = Unit.usd, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
self.endpoint = "https://api.strike.me"
# bearer auth with settings.mint_strike_key

View File

@@ -1,6 +1,5 @@
import asyncio
import copy
import math
import time
from typing import Dict, List, Mapping, Optional, Tuple
@@ -493,10 +492,10 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
if mint_quote:
# internal transaction, validate and return amount from
# associated mint quote and demand zero fees
assert (
Amount(unit, mint_quote.amount).to(Unit.msat).amount
== invoice_obj.amount_msat
), "amounts do not match"
# assert (
# Amount(unit, mint_quote.amount).to(Unit.msat).amount
# == invoice_obj.amount_msat
# ), "amounts do not match"
assert request == mint_quote.request, "bolt11 requests do not match"
assert mint_quote.unit == melt_quote.unit, "units do not match"
assert mint_quote.method == method.name, "methods do not match"
@@ -506,7 +505,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
payment_quote = PaymentQuoteResponse(
checking_id=mint_quote.checking_id,
amount=Amount(unit, mint_quote.amount),
fee=Amount(unit=Unit.msat, amount=0),
fee=Amount(unit, amount=0),
)
logger.info(
f"Issuing internal melt quote: {request} ->"
@@ -622,11 +621,12 @@ class Ledger(LedgerVerification, LedgerSpendingConditions):
bolt11_request = melt_quote.request
invoice_obj = bolt11.decode(bolt11_request)
assert invoice_obj.amount_msat, "invoice has no amount."
invoice_amount_sat = math.ceil(invoice_obj.amount_msat / 1000)
assert (
Amount(Unit[melt_quote.unit], mint_quote.amount).to(Unit.sat).amount
== invoice_amount_sat
), "amounts do not match"
# invoice_amount_sat = math.ceil(invoice_obj.amount_msat / 1000)
# assert (
# Amount(Unit[melt_quote.unit], mint_quote.amount).to(Unit.sat).amount
# == invoice_amount_sat
# ), "amounts do not match"
assert mint_quote.amount == melt_quote.amount, "amounts do not match"
assert bolt11_request == mint_quote.request, "bolt11 requests do not match"
assert mint_quote.unit == melt_quote.unit, "units do not match"
assert mint_quote.method == melt_quote.method, "methods do not match"

View File

@@ -3,6 +3,7 @@
import asyncio
import importlib
from typing import Dict
from loguru import logger
@@ -10,6 +11,7 @@ from ..core.base import Method, Unit
from ..core.db import Database
from ..core.migrations import migrate_databases
from ..core.settings import settings
from ..lightning.base import LightningBackend
from ..mint import migrations
from ..mint.crud import LedgerCrudSqlite
from ..mint.ledger import Ledger
@@ -31,23 +33,24 @@ for key, value in settings.dict().items():
logger.debug(f"{key}: {value}")
wallets_module = importlib.import_module("cashu.lightning")
lightning_backend = getattr(wallets_module, settings.mint_lightning_backend)()
assert settings.mint_private_key is not None, "No mint private key set."
backends: Dict[Method, Dict[Unit, LightningBackend]] = {}
if settings.mint_backend_bolt11_sat:
backend_bolt11_sat = getattr(wallets_module, settings.mint_backend_bolt11_sat)(
unit=Unit.sat
)
backends.setdefault(Method.bolt11, {})[Unit.sat] = backend_bolt11_sat
if settings.mint_backend_bolt11_usd:
backend_bolt11_usd = getattr(wallets_module, settings.mint_backend_bolt11_usd)(
unit=Unit.usd
)
backends.setdefault(Method.bolt11, {})[Unit.usd] = backend_bolt11_usd
if not backends:
raise Exception("No backends are set.")
if not settings.mint_private_key:
raise Exception("No mint private key is set.")
# strike_backend = getattr(wallets_module, "StrikeUSDWallet")()
# backends = {
# Method.bolt11: {Unit.sat: lightning_backend, Unit.usd: strike_backend},
# }
# backends = {
# Method.bolt11: {Unit.sat: lightning_backend, Unit.msat: lightning_backend},
# }
# backends = {
# Method.bolt11: {Unit.sat: lightning_backend, Unit.msat: lightning_backend,
# }
backends = {
Method.bolt11: {Unit.sat: lightning_backend},
}
ledger = Ledger(
db=Database("mint", settings.mint_database),
seed=settings.mint_private_key,

View File

@@ -265,10 +265,9 @@ async def receive_command(
if token:
tokenObj: TokenV3 = deserialize_token_from_string(token)
await verify_mints(wallet, tokenObj)
balance = await receive(wallet, tokenObj)
await receive(wallet, tokenObj)
elif nostr:
await receive_nostr(wallet)
balance = wallet.available_balance
elif all:
reserved_proofs = await get_reserved_proofs(wallet.db)
balance = None
@@ -278,10 +277,10 @@ async def receive_command(
token = await wallet.serialize_proofs(proofs)
tokenObj = deserialize_token_from_string(token)
await verify_mints(wallet, tokenObj)
balance = await receive(wallet, tokenObj)
await receive(wallet, tokenObj)
else:
raise Exception("enter token or use either flag --nostr or --all.")
assert balance
balance = wallet.available_balance
return ReceiveResponse(initial_balance=initial_balance, balance=balance)
@@ -359,15 +358,17 @@ async def pending(
reserved_date = datetime.utcfromtimestamp(
int(grouped_proofs[0].time_reserved) # type: ignore
).strftime("%Y-%m-%d %H:%M:%S")
result.update({
f"{i}": {
"amount": sum_proofs(grouped_proofs),
"time": reserved_date,
"ID": key,
"token": token,
"mint": mint,
result.update(
{
f"{i}": {
"amount": sum_proofs(grouped_proofs),
"time": reserved_date,
"ID": key,
"token": token,
"mint": mint,
}
}
})
)
return PendingResponse(pending_token=result)
@@ -412,14 +413,16 @@ async def wallets():
if w == wallet.name:
active_wallet = True
if active_wallet:
result.update({
f"{w}": {
"balance": sum_proofs(wallet.proofs),
"available": sum_proofs([
p for p in wallet.proofs if not p.reserved
]),
result.update(
{
f"{w}": {
"balance": sum_proofs(wallet.proofs),
"available": sum_proofs(
[p for p in wallet.proofs if not p.reserved]
),
}
}
})
)
except Exception:
pass
return WalletsResponse(wallets=result)

View File

@@ -184,7 +184,7 @@ async def cli(ctx: Context, host: str, walletname: str, unit: str, tests: bool):
async def pay(ctx: Context, invoice: str, yes: bool):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
print_balance(ctx)
await print_balance(ctx)
quote = await wallet.get_pay_amount_with_fees(invoice)
logger.debug(f"Quote: {quote}")
total_amount = quote.amount + quote.fee_reserve
@@ -219,7 +219,7 @@ async def pay(ctx: Context, invoice: str, yes: bool):
print(f" (Preimage: {melt_response.payment_preimage}).")
else:
print(".")
print_balance(ctx)
await print_balance(ctx)
@cli.command("invoice", help="Create Lighting invoice.")
@@ -242,11 +242,12 @@ async def pay(ctx: Context, invoice: str, yes: bool):
)
@click.pass_context
@coro
async def invoice(ctx: Context, amount: int, id: str, split: int, no_check: bool):
async def invoice(ctx: Context, amount: float, id: str, split: int, no_check: bool):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_mint()
print_balance(ctx)
await print_balance(ctx)
amount = int(amount * 100) if wallet.unit == Unit.usd else int(amount)
print(f"Requesting invoice for {wallet.unit.str(amount)} {wallet.unit}.")
# in case the user wants a specific split, we create a list of amounts
optional_split = None
if split:
@@ -305,7 +306,7 @@ async def invoice(ctx: Context, amount: int, id: str, split: int, no_check: bool
elif amount and id:
await wallet.mint(amount, split=optional_split, id=id)
print("")
print_balance(ctx)
await print_balance(ctx)
return
@@ -474,7 +475,7 @@ async def send_command(
await send_nostr(
wallet, amount=amount, pubkey=nostr or nopt, verbose=verbose, yes=yes
)
print_balance(ctx)
await print_balance(ctx)
@cli.command("receive", help="Receive tokens.")
@@ -508,8 +509,9 @@ async def receive_cli(
mint_url, os.path.join(settings.cashu_dir, wallet.name)
)
await verify_mint(mint_wallet, mint_url)
receive_wallet = await receive(wallet, tokenObj)
ctx.obj["WALLET"] = receive_wallet
await receive(wallet, tokenObj)
elif nostr:
await receive_nostr(wallet)
# exit on keypress
@@ -530,11 +532,12 @@ async def receive_cli(
mint_url, os.path.join(settings.cashu_dir, wallet.name)
)
await verify_mint(mint_wallet, mint_url)
await receive(wallet, tokenObj)
receive_wallet = await receive(wallet, tokenObj)
ctx.obj["WALLET"] = receive_wallet
else:
print("Error: enter token or use either flag --nostr or --all.")
return
print_balance(ctx)
await print_balance(ctx)
@cli.command("burn", help="Burn spent tokens.")
@@ -586,7 +589,7 @@ async def burn(ctx: Context, token: str, all: bool, force: bool, delete: str):
for i in range(0, len(proofs), settings.proofs_batch_size)
]:
await wallet.invalidate(_proofs, check_spendable=True)
print_balance(ctx)
await print_balance(ctx)
@cli.command("pending", help="Show pending tokens.")
@@ -865,7 +868,7 @@ async def restore(ctx: Context, to: int, batch: int):
await wallet.restore_wallet_from_mnemonic(mnemonic, to=to, batch=batch)
await wallet.load_proofs()
print_balance(ctx)
await print_balance(ctx)
@cli.command("selfpay", help="Refresh tokens.")

View File

@@ -10,8 +10,9 @@ from ...wallet.crud import get_keysets
from ...wallet.wallet import Wallet as Wallet
def print_balance(ctx: Context):
async def print_balance(ctx: Context):
wallet: Wallet = ctx.obj["WALLET"]
await wallet.load_proofs(reload=True, unit=wallet.unit)
print(f"Balance: {wallet.unit.str(wallet.available_balance)}")

View File

@@ -35,7 +35,7 @@ async def list_mints(wallet: Wallet):
return mints
async def redeem_TokenV3_multimint(wallet: Wallet, token: TokenV3):
async def redeem_TokenV3_multimint(wallet: Wallet, token: TokenV3) -> Wallet:
"""
Helper function to iterate thruogh a token with multiple mints and redeem them from
these mints one keyset at a time.
@@ -58,6 +58,9 @@ async def redeem_TokenV3_multimint(wallet: Wallet, token: TokenV3):
_, _ = await mint_wallet.redeem(redeem_proofs)
print(f"Received {mint_wallet.unit.str(sum_proofs(redeem_proofs))}")
# return the last mint_wallet
return mint_wallet
def serialize_TokenV2_to_TokenV3(tokenv2: TokenV2):
"""Helper function to receive legacy TokenV2 tokens.
@@ -120,7 +123,7 @@ def deserialize_token_from_string(token: str) -> TokenV3:
async def receive(
wallet: Wallet,
tokenObj: TokenV3,
):
) -> Wallet:
logger.debug(f"receive: {tokenObj}")
proofs = [p for t in tokenObj.token for p in t.proofs]
@@ -128,7 +131,7 @@ async def receive(
if includes_mint_info:
# redeem tokens with new wallet instances
await redeem_TokenV3_multimint(
mint_wallet = await redeem_TokenV3_multimint(
wallet,
tokenObj,
)
@@ -154,7 +157,7 @@ async def receive(
# reload main wallet so the balance updates
await wallet.load_proofs(reload=True)
return wallet.available_balance
return mint_wallet
async def send(

View File

@@ -8,7 +8,7 @@ services:
ports:
- "3338:3338"
environment:
- MINT_LIGHTNING_BACKEND=FakeWallet
- MINT_BACKEND_BOLT11_SAT=FakeWallet
- MINT_LISTEN_HOST=0.0.0.0
- MINT_LISTEN_PORT=3338
- MINT_PRIVATE_KEY=TEST_PRIVATE_KEY

View File

@@ -25,7 +25,7 @@ async def get_random_invoice_data():
wallets_module = importlib.import_module("cashu.lightning")
wallet_class = getattr(wallets_module, settings.mint_lightning_backend)
wallet_class = getattr(wallets_module, settings.mint_backend_bolt11_sat)
WALLET = wallet_class()
is_fake: bool = WALLET.__class__.__name__ == "FakeWallet"
is_regtest: bool = not is_fake