fix: Boltzclient fundingsource. use a hashed wallet_name (#3673)

This commit is contained in:
dni ⚡ 2025-12-17 13:57:05 +01:00 committed by GitHub
parent 606ee215b4
commit a0f65f4cda
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 86 additions and 36 deletions

View file

@ -23,3 +23,10 @@ mypy.ini
package-lock.json package-lock.json
package.json package.json
pytest.ini pytest.ini
.mypy_cache
.github
.pytest_cache
.vscode
bin
dist

View file

@ -601,7 +601,6 @@ class BreezLiquidSdkFundingSource(LNbitsSettings):
class BoltzFundingSource(LNbitsSettings): class BoltzFundingSource(LNbitsSettings):
boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002") boltz_client_endpoint: str | None = Field(default="127.0.0.1:9002")
boltz_client_macaroon: str | None = Field(default=None) boltz_client_macaroon: str | None = Field(default=None)
boltz_client_wallet: str | None = Field(default="lnbits")
boltz_client_password: str = Field(default="") boltz_client_password: str = Field(default="")
boltz_client_cert: str | None = Field(default=None) boltz_client_cert: str | None = Field(default=None)
boltz_mnemonic: str | None = Field(default=None) boltz_mnemonic: str | None = Field(default=None)

File diff suppressed because one or more lines are too long

View file

@ -163,11 +163,9 @@ window.app.component('lnbits-admin-funding-sources', {
boltz_client_endpoint: 'Endpoint', boltz_client_endpoint: 'Endpoint',
boltz_client_macaroon: 'Admin Macaroon path or hex', boltz_client_macaroon: 'Admin Macaroon path or hex',
boltz_client_cert: 'Certificate path or hex', boltz_client_cert: 'Certificate path or hex',
boltz_client_wallet: 'Wallet Name',
boltz_client_password: 'Wallet Password (can be empty)', boltz_client_password: 'Wallet Password (can be empty)',
boltz_mnemonic: { boltz_mnemonic: {
label: 'Liquid mnemonic (copy into greenwallet)', label: 'Liquid mnemonic (copy into greenwallet)',
readonly: true,
copy: true, copy: true,
qrcode: true qrcode: true
} }

View file

@ -5,7 +5,7 @@ from bolt11.decode import decode
from grpc.aio import AioRpcError from grpc.aio import AioRpcError
from loguru import logger from loguru import logger
from lnbits.helpers import normalize_endpoint from lnbits.helpers import normalize_endpoint, sha256s
from lnbits.settings import settings from lnbits.settings import settings
from lnbits.wallets.boltz_grpc_files import boltzrpc_pb2, boltzrpc_pb2_grpc from lnbits.wallets.boltz_grpc_files import boltzrpc_pb2, boltzrpc_pb2_grpc
from lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc import grpc from lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc import grpc
@ -38,10 +38,6 @@ class BoltzWallet(Wallet):
raise ValueError( raise ValueError(
"cannot initialize BoltzWallet: missing boltz_client_endpoint" "cannot initialize BoltzWallet: missing boltz_client_endpoint"
) )
if not settings.boltz_client_wallet:
raise ValueError(
"cannot initialize BoltzWallet: missing boltz_client_wallet"
)
self.endpoint = normalize_endpoint( self.endpoint = normalize_endpoint(
settings.boltz_client_endpoint, add_proto=True settings.boltz_client_endpoint, add_proto=True
@ -63,31 +59,20 @@ class BoltzWallet(Wallet):
self.rpc = boltzrpc_pb2_grpc.BoltzStub(channel) self.rpc = boltzrpc_pb2_grpc.BoltzStub(channel)
self.wallet_id = 0 self.wallet_id = 0
self.wallet_name = "lnbits"
# Auto-create wallet if running in Docker mode if settings.boltz_mnemonic: # restore wallet from mnemonic
async def _init_boltz_wallet(): self._init_wallet_task = asyncio.create_task(
try: self._restore_boltz_wallet(
wallet_name = settings.boltz_client_wallet or "lnbits" settings.boltz_mnemonic, settings.boltz_client_password
mnemonic = await self._fetch_wallet(wallet_name) )
if mnemonic: )
logger.info( else: # create new wallet
"✅ Mnemonic found for Boltz wallet, saving to settings" self._init_wallet_task = asyncio.create_task(self._create_boltz_wallet())
)
settings.boltz_mnemonic = mnemonic
from lnbits.core.crud.settings import set_settings_field
await set_settings_field("boltz_mnemonic", mnemonic)
else:
logger.warning("⚠️ No mnemonic returned from Boltz")
except Exception as e:
logger.error(f"❌ Failed to auto-create Boltz wallet: {e}")
self._init_wallet_task = asyncio.create_task(_init_boltz_wallet())
async def status(self) -> StatusResponse: async def status(self) -> StatusResponse:
try: try:
request = boltzrpc_pb2.GetWalletRequest(name=settings.boltz_client_wallet) request = boltzrpc_pb2.GetWalletRequest(name=self.wallet_name)
response: boltzrpc_pb2.Wallet = await self.rpc.GetWallet( response: boltzrpc_pb2.Wallet = await self.rpc.GetWallet(
request, metadata=self.metadata request, metadata=self.metadata
) )
@ -253,24 +238,85 @@ class BoltzWallet(Wallet):
) )
await asyncio.sleep(5) await asyncio.sleep(5)
async def _fetch_wallet(self, wallet_name: str) -> str | None: async def _check_wallet_exists(
self, wallet_name: str
) -> boltzrpc_pb2.Wallet | None:
try: try:
request = boltzrpc_pb2.GetWalletRequest(name=wallet_name) request = boltzrpc_pb2.GetWalletRequest(name=wallet_name)
response = await self.rpc.GetWallet(request, metadata=self.metadata) response = await self.rpc.GetWallet(request, metadata=self.metadata)
logger.info(f"Wallet '{wallet_name}' already exists with ID {response.id}") logger.info(f"Wallet '{wallet_name}' already exists with ID {response.id}")
return settings.boltz_mnemonic return response
except AioRpcError as exc: except AioRpcError as exc:
details = exc.details() or "unknown error"
if exc.code() != grpc.StatusCode.NOT_FOUND: if exc.code() != grpc.StatusCode.NOT_FOUND:
logger.error(f"Error checking wallet existence: {details}") logger.warning(f"Wallet '{wallet_name}' does not exist.")
raise return None
logger.error(f"Error checking wallet existence: {exc.details()}")
return None
async def _delete_wallet(self, wallet_id: int) -> None:
logger.info(f"Deleting wallet '{wallet_id}'")
delete_request = boltzrpc_pb2.RemoveWalletRequest(id=wallet_id)
await self.rpc.RemoveWallet(delete_request, metadata=self.metadata)
async def _restore_wallet(self, wallet_name: str, mnemonic: str, password: str):
logger.info(f"Restoring wallet '{wallet_name}' from mnemonic")
credentials = boltzrpc_pb2.WalletCredentials(mnemonic=mnemonic)
params = boltzrpc_pb2.WalletParams(
name=wallet_name,
currency=boltzrpc_pb2.LBTC,
password=password,
)
restore_request = boltzrpc_pb2.ImportWalletRequest(
credentials=credentials, params=params
)
response = await self.rpc.ImportWallet(restore_request, metadata=self.metadata)
return response
async def _create_wallet(self, wallet_name: str, password: str) -> str:
logger.info(f"Creating new wallet '{wallet_name}'") logger.info(f"Creating new wallet '{wallet_name}'")
params = boltzrpc_pb2.WalletParams( params = boltzrpc_pb2.WalletParams(
name=wallet_name, name=wallet_name,
currency=boltzrpc_pb2.LBTC, currency=boltzrpc_pb2.LBTC,
password=settings.boltz_client_password, password=password,
) )
create_request = boltzrpc_pb2.CreateWalletRequest(params=params) create_request = boltzrpc_pb2.CreateWalletRequest(params=params)
response = await self.rpc.CreateWallet(create_request, metadata=self.metadata) response = await self.rpc.CreateWallet(create_request, metadata=self.metadata)
return response.mnemonic return response.mnemonic
async def _restore_boltz_wallet(self, mnemonic: str, password: str):
try:
# delete the wallet with to name without hashing first if it exists
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
await self._delete_wallet(wallet.id)
# recreate the wallet with the hashed name
self.wallet_name = sha256s(mnemonic + password)
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
logger.success("✅ Boltz wallet exists.")
return
await self._restore_wallet(self.wallet_name, mnemonic, password)
logger.success("✅ Boltz wallet restored from existing mnemonic")
except Exception as e:
logger.error(f"❌ Failed to restore Boltz wallet: {e}")
async def _create_boltz_wallet(self):
try:
# delete the wallet with to name without hashing first if it exists
wallet = await self._check_wallet_exists(self.wallet_name)
if wallet:
await self._delete_wallet(wallet.id)
logger.info("No Mnemonic found for Boltz wallet, creating wallet...")
mnemonic = await self._create_wallet(
self.wallet_name, settings.boltz_client_password
)
logger.success("✅ Boltz wallet created successfully")
settings.boltz_mnemonic = mnemonic
from lnbits.core.crud.settings import set_settings_field
await set_settings_field("boltz_mnemonic", mnemonic)
except Exception as e:
logger.error(f"❌ Failed to create Boltz wallet: {e}")