Files
plm-lottery/app/wallet/address.py
T
davideandClaude Opus 5 5c9ccc0344 Reject withdrawal addresses that aren't PLM
embit's Script.from_address accepts a well-formed bech32 address from any
chain: a Bitcoin bc1... parses into a perfectly valid witness program. So a
withdrawal to a BTC address built, signed and broadcast normally on PLM, and
the funds landed on a script nobody holds the key for — silently, with no
error anywhere. A malformed address fared slightly better only in that it
crashed the request with an unhandled 500.

is_valid_plm_address checks the HRP as well as the parse, and runs first in
request_withdrawal, before a single UTXO is touched. It matches what the
withdrawal form already told the user (bech32 plm1q... only).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 21:45:07 +02:00

28 lines
976 B
Python

"""Validation for PLM addresses supplied by the user (withdrawal destinations).
embit's `Script.from_address` accepts a well-formed bech32 address from *any*
chain — a Bitcoin `bc1...` parses fine and yields a perfectly valid witness
program — so parse-success alone is not a sufficient check here: a withdrawal
to a `bc1...` address would build, sign and broadcast normally on PLM and land
on a script nobody holds the key for. The HRP check below is what makes the
destination actually PLM, and it matches what the withdrawal form already
tells the user (bech32 `plm1q...` only).
"""
from embit import script
from embit.base import EmbitError
from app.wallet.plm_network import PLM_MAINNET
_BECH32_PREFIX = PLM_MAINNET["bech32"] + "1"
def is_valid_plm_address(address: str) -> bool:
if not address.startswith(_BECH32_PREFIX):
return False
try:
script.Script.from_address(address)
except EmbitError:
return False
return True