fix: include fiat amount in BTCPay webhook payload; quiet wallet-rpc spam

Mirror of xmrcheckout commit eb15c52. Same two bugs, same fix.

1. _build_payload now emits amount (fiat), currency, and amount_crypto so Medusa's capture workflow captures the right value instead of 0 (which leaves payments authorized forever).

2. get_status() no longer calls set_daemon without an open wallet (was flooding logs with RPC -13). _daemon_height() probe is sufficient for daemon reachability.

3. Silenced monero.backends.jsonrpc.wallet logger for expected transient close_wallet errors.
This commit is contained in:
jwinterm
2026-04-18 16:31:44 -04:00
parent eb0075f507
commit 240c2b2b9f
3 changed files with 35 additions and 17 deletions
+17 -1
View File
@@ -118,6 +118,10 @@ def _build_payload(
invoice: Invoice,
manually_marked: bool,
) -> dict[str, object]:
metadata = invoice.metadata_json or {}
quote = metadata.get("quote") if isinstance(metadata, dict) else None
fiat_amount = quote.get("fiat_amount") if isinstance(quote, dict) else None
fiat_currency = quote.get("fiat_currency") if isinstance(quote, dict) else None
return {
"type": event_type,
"timestamp": int(time.time()),
@@ -127,7 +131,19 @@ def _build_payload(
"overPaid": False,
"partiallyPaid": False,
"afterExpiration": _after_expiration(invoice),
"metadata": invoice.metadata_json or {},
"metadata": metadata,
# Fiat amount/currency so downstream processors (e.g. Medusa) can
# capture at the right number. Omitting this defaults Medusa's capture
# to 0 which leaves captured_at NULL and payment_collection stuck at
# authorized forever.
"amount": str(fiat_amount) if fiat_amount is not None else None,
"currency": fiat_currency,
# Crypto amount is also useful for reconciliation in some downstreams.
"amount_crypto": (
str(invoice.amount_xmr)
if getattr(invoice, "amount_xmr", None) is not None
else None
),
}
+9 -16
View File
@@ -99,6 +99,14 @@ class MoneroWalletService:
self._wallet_dir = MONERO_WALLET_RPC_WALLET_DIR.strip()
def get_status(self) -> dict[str, str | int | None]:
# Probe each wallet-rpc backend with get_version (works without an open
# wallet). Probe daemon reachability via direct HTTP get_height, which
# bypasses wallet-rpc. We previously also called set_daemon here as a
# "secondary daemon check", but set_daemon requires an open wallet —
# on backends that currently hold no wallet (most of the time for idle
# reconcilers) that produces a constant stream of RPC -13 "No wallet
# file" errors from the python-monero logger. The get_version +
# _daemon_height pair is sufficient and doesn't require any wallet.
daemon_height = self._daemon_height()
for backend in self._backends:
try:
@@ -109,24 +117,9 @@ class MoneroWalletService:
"daemon": "ok" if daemon_height is not None else "unreachable",
"daemon_height": daemon_height,
}
if self._daemon_address:
try:
self._backends[0].client.raw_request(
"set_daemon",
{"address": self._daemon_address},
)
except RPCError as exc:
message = str(exc)
if "no connection to daemon" in message or "no_connection_to_daemon" in message:
return {
"wallet_rpc": "ok",
"daemon": "unreachable",
"daemon_height": daemon_height,
}
return {
"wallet_rpc": "ok",
"daemon": "ok" if self._daemon_address else "unknown",
"daemon": "ok" if daemon_height is not None else "unreachable",
"daemon_height": daemon_height,
}
+9
View File
@@ -28,6 +28,15 @@ def main() -> None:
level_name = "INFO"
level = getattr(logging, level_name.upper(), logging.INFO)
logging.basicConfig(level=level)
# Silence expected RPC -13 ("No wallet file") spam from the python-monero
# library. Those happen routinely when close_wallet is called on an idle
# backend (by _ensure_wallet_open) and are handled by our retry logic;
# they are not actionable errors and were drowning real log output.
# Real wallet-rpc problems still bubble up as exceptions which we log
# explicitly through logger.error / logger.exception.
logging.getLogger("monero.backends.jsonrpc.wallet").setLevel(logging.CRITICAL)
while True:
status_db: Session | None = None
try: