test: add boltz fundingsource to regtest (#3677)
Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com>
This commit is contained in:
@@ -337,7 +337,7 @@ async def api_payment(payment_hash, x_api_key: str | None = Header(None)):
|
||||
return {"paid": False, "status": "failed"}
|
||||
|
||||
try:
|
||||
status = await payment.check_status()
|
||||
payment = await update_pending_payment(payment)
|
||||
except Exception:
|
||||
if wallet and wallet.id == payment.wallet_id:
|
||||
return {"paid": False, "details": payment}
|
||||
@@ -346,7 +346,7 @@ async def api_payment(payment_hash, x_api_key: str | None = Header(None)):
|
||||
if wallet and wallet.id == payment.wallet_id:
|
||||
return {
|
||||
"paid": payment.success,
|
||||
"status": f"{status!s}",
|
||||
"status": f"{payment.status!s}",
|
||||
"preimage": payment.preimage,
|
||||
"details": payment,
|
||||
}
|
||||
|
||||
+70
-38
@@ -43,12 +43,13 @@ class BoltzWallet(Wallet):
|
||||
settings.boltz_client_endpoint, add_proto=True
|
||||
)
|
||||
|
||||
self.metadata = None
|
||||
if settings.boltz_client_macaroon:
|
||||
self.metadata = [
|
||||
("macaroon", load_macaroon(settings.boltz_client_macaroon))
|
||||
]
|
||||
else:
|
||||
self.metadata = None
|
||||
try:
|
||||
macaroon = load_macaroon(settings.boltz_client_macaroon)
|
||||
self.metadata = [("macaroon", macaroon)]
|
||||
except Exception as e:
|
||||
logger.error(f"BoltzWallet failed to load macaroon: {e}")
|
||||
|
||||
if settings.boltz_client_cert:
|
||||
cert = open(settings.boltz_client_cert, "rb").read()
|
||||
@@ -60,17 +61,18 @@ class BoltzWallet(Wallet):
|
||||
self.rpc = boltzrpc_pb2_grpc.BoltzStub(channel)
|
||||
self.wallet_id = 0
|
||||
self.wallet_name = "lnbits"
|
||||
|
||||
if settings.boltz_mnemonic: # restore wallet from mnemonic
|
||||
self._init_wallet_task = asyncio.create_task(
|
||||
self._restore_boltz_wallet(
|
||||
settings.boltz_mnemonic, settings.boltz_client_password
|
||||
)
|
||||
)
|
||||
else: # create new wallet
|
||||
self._init_wallet_task = asyncio.create_task(self._create_boltz_wallet())
|
||||
self.wallet_ready = False
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
if self.wallet_ready is False:
|
||||
self.wallet_ready = True
|
||||
if settings.boltz_mnemonic: # restore wallet from mnemonic
|
||||
await self._restore_boltz_wallet(
|
||||
settings.boltz_mnemonic,
|
||||
settings.boltz_client_password,
|
||||
)
|
||||
else: # create new wallet
|
||||
await self._create_boltz_wallet()
|
||||
try:
|
||||
request = boltzrpc_pb2.GetWalletRequest(name=self.wallet_name)
|
||||
response: boltzrpc_pb2.Wallet = await self.rpc.GetWallet(
|
||||
@@ -111,12 +113,18 @@ class BoltzWallet(Wallet):
|
||||
try:
|
||||
response = await self.rpc.CreateReverseSwap(request, metadata=self.metadata)
|
||||
except AioRpcError as exc:
|
||||
logger.warning(exc)
|
||||
return InvoiceResponse(ok=False, error_message=exc.details())
|
||||
fee_msat = response.routing_fee_milli_sat
|
||||
return InvoiceResponse(
|
||||
ok=True, checking_id=response.id, payment_request=response.invoice
|
||||
ok=True,
|
||||
checking_id=response.id,
|
||||
payment_request=response.invoice,
|
||||
fee_msat=fee_msat,
|
||||
)
|
||||
|
||||
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
|
||||
|
||||
pair = boltzrpc_pb2.Pair(**{"from": boltzrpc_pb2.LBTC})
|
||||
try:
|
||||
pair_info: boltzrpc_pb2.PairInfo
|
||||
@@ -128,8 +136,9 @@ class BoltzWallet(Wallet):
|
||||
|
||||
if not invoice.amount_msat:
|
||||
raise ValueError("amountless invoice")
|
||||
|
||||
service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100
|
||||
estimate = service_fee + pair_info.fees.miner_fees * 1000
|
||||
estimate = int(service_fee + pair_info.fees.miner_fees * 1000)
|
||||
if estimate > fee_limit_msat:
|
||||
error = f"fee of {estimate} msat exceeds limit of {fee_limit_msat} msat"
|
||||
|
||||
@@ -151,11 +160,12 @@ class BoltzWallet(Wallet):
|
||||
if response.id == "":
|
||||
# note that there is no way to provide a checking id here,
|
||||
# but there is no need since it immediately is considered as successfull
|
||||
return PaymentResponse(
|
||||
ok=True,
|
||||
checking_id=response.id,
|
||||
logger.warning(
|
||||
"Boltz invoice paid directly on liquid network using magic routing"
|
||||
)
|
||||
return PaymentResponse(ok=True, checking_id=invoice.payment_hash)
|
||||
except AioRpcError as exc:
|
||||
logger.warning(exc)
|
||||
return PaymentResponse(ok=False, error_message=exc.details())
|
||||
|
||||
try:
|
||||
@@ -165,10 +175,15 @@ class BoltzWallet(Wallet):
|
||||
info_request, metadata=self.metadata
|
||||
):
|
||||
if info.swap.state == boltzrpc_pb2.SUCCESSFUL:
|
||||
fee_msat = (info.swap.onchain_fee + info.swap.service_fee) * 1000
|
||||
logger.debug(
|
||||
f"Boltz swap successful, status: {info.swap.status}"
|
||||
f"fee_msat: {fee_msat}"
|
||||
)
|
||||
return PaymentResponse(
|
||||
ok=True,
|
||||
checking_id=response.id,
|
||||
fee_msat=(info.swap.onchain_fee + info.swap.service_fee) * 1000,
|
||||
checking_id=invoice.payment_hash,
|
||||
fee_msat=fee_msat,
|
||||
preimage=info.swap.preimage,
|
||||
)
|
||||
elif info.swap.error != "":
|
||||
@@ -177,21 +192,29 @@ class BoltzWallet(Wallet):
|
||||
ok=False, error_message="stream stopped unexpectedly"
|
||||
)
|
||||
except AioRpcError as exc:
|
||||
logger.warning(exc)
|
||||
return PaymentResponse(ok=False, error_message=exc.details())
|
||||
|
||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||
try:
|
||||
request = boltzrpc_pb2.GetSwapInfoRequest(id=checking_id)
|
||||
response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo(
|
||||
boltzrpc_pb2.GetSwapInfoRequest(id=checking_id), metadata=self.metadata
|
||||
request,
|
||||
metadata=self.metadata,
|
||||
)
|
||||
swap = response.reverse_swap
|
||||
except AioRpcError:
|
||||
except AioRpcError as exc:
|
||||
logger.warning(exc)
|
||||
return PaymentPendingStatus()
|
||||
if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL:
|
||||
fee_msat = (
|
||||
swap.service_fee + swap.onchain_fee
|
||||
) * 1000 + swap.routing_fee_msat
|
||||
logger.debug(
|
||||
f"Boltz swap successful, status: {swap.status}, fee_msat: {fee_msat}"
|
||||
)
|
||||
return PaymentSuccessStatus(
|
||||
fee_msat=(
|
||||
(swap.service_fee + swap.onchain_fee) * 1000 + swap.routing_fee_msat
|
||||
),
|
||||
fee_msat=fee_msat,
|
||||
preimage=swap.preimage,
|
||||
)
|
||||
elif swap.state == boltzrpc_pb2.SwapState.PENDING:
|
||||
@@ -201,18 +224,23 @@ class BoltzWallet(Wallet):
|
||||
|
||||
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||
try:
|
||||
checking_id_bytes = bytes.fromhex(checking_id)
|
||||
request = boltzrpc_pb2.GetSwapInfoRequest(payment_hash=checking_id_bytes)
|
||||
response: boltzrpc_pb2.GetSwapInfoResponse = await self.rpc.GetSwapInfo(
|
||||
boltzrpc_pb2.GetSwapInfoRequest(
|
||||
payment_hash=bytes.fromhex(checking_id)
|
||||
),
|
||||
request,
|
||||
metadata=self.metadata,
|
||||
)
|
||||
swap = response.swap
|
||||
except AioRpcError:
|
||||
except AioRpcError as exc:
|
||||
logger.warning(exc)
|
||||
return PaymentPendingStatus()
|
||||
if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL:
|
||||
fee_msat = (swap.service_fee + swap.onchain_fee) * 1000
|
||||
logger.debug(
|
||||
f"Boltz swap successful, status: {swap.status}, fee_msat: {fee_msat}"
|
||||
)
|
||||
return PaymentSuccessStatus(
|
||||
fee_msat=(swap.service_fee + swap.onchain_fee) * 1000,
|
||||
fee_msat=fee_msat,
|
||||
preimage=swap.preimage,
|
||||
)
|
||||
elif swap.state == boltzrpc_pb2.SwapState.PENDING:
|
||||
@@ -229,7 +257,16 @@ class BoltzWallet(Wallet):
|
||||
request, metadata=self.metadata
|
||||
):
|
||||
reverse = info.reverse_swap
|
||||
if reverse and reverse.state == boltzrpc_pb2.SUCCESSFUL:
|
||||
if (
|
||||
reverse
|
||||
and reverse.state == boltzrpc_pb2.SUCCESSFUL
|
||||
and reverse.status == "invoice.settled"
|
||||
):
|
||||
fee_msat = ((reverse.service_fee + reverse.onchain_fee) * 1000,)
|
||||
logger.debug(
|
||||
f"Boltz reverse swap settled: {reverse.id}, "
|
||||
f"fee_msat: {fee_msat}"
|
||||
)
|
||||
yield reverse.id
|
||||
except Exception as exc:
|
||||
logger.error(
|
||||
@@ -244,13 +281,8 @@ class BoltzWallet(Wallet):
|
||||
try:
|
||||
request = boltzrpc_pb2.GetWalletRequest(name=wallet_name)
|
||||
response = await self.rpc.GetWallet(request, metadata=self.metadata)
|
||||
logger.info(f"Wallet '{wallet_name}' already exists with ID {response.id}")
|
||||
return response
|
||||
except AioRpcError as exc:
|
||||
if exc.code() != grpc.StatusCode.NOT_FOUND:
|
||||
logger.warning(f"Wallet '{wallet_name}' does not exist.")
|
||||
return None
|
||||
logger.error(f"Error checking wallet existence: {exc.details()}")
|
||||
except AioRpcError:
|
||||
return None
|
||||
|
||||
async def _delete_wallet(self, wallet_id: int) -> None:
|
||||
|
||||
Reference in New Issue
Block a user