fix(send): accept P2SH/multisig recipients in the send + URI address gates
Same defect class as the import-key fix: a hardcoded prefix/length pre-filter
layered over the checksum validators rejected valid addresses before the daemon
saw them. The send-screen recipient gate required a[0]=='R', and the payment-URI
parser accepted only 'R'/'t' with rigid length bands — so every valid P2SH /
multisig address (DragonX SCRIPT_ADDRESS=85 → 'b…') was silently refused, leaving
the Send button disabled with no usable recipient.
Centralize recipient recognition in util/address_validation:
- isTransparentAddress: Base58Check with a 21-byte version+hash160 payload —
covers P2PKH ('R…', v60) AND P2SH ('b…', v85) on every network, rejects WIF
keys / typos by real checksum.
- isShieldedAddress: Bech32 + a Sapling payment-address HRP (zs / ztestsapling /
zregtestsapling), distinguishing a payment address from a viewing key.
- isValidRecipientAddress: either of the above.
send_tab's two validity helpers (the single choke point for all 5 call sites) and
the payment-URI format check now route through these. The URI parser now
checksum-validates the recipient (fail-fast on transcription errors) rather than
being prefix/length-only.
Tests use real checksummed vectors (P2PKH/P2SH/shielded, WIF- and typo-rejection);
testPaymentUri updated off its old fake fixed-char addresses. Suite green (1/1).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -148,14 +148,14 @@ static double GetAvailableBalance(App* app) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Recipient validity = prefix/length pre-filter AND a real encoding-checksum check, so a
|
||||
// transcription error that still matches the prefix/length is no longer labelled "Valid".
|
||||
// The checksum verifiers are version-agnostic, so they never reject a genuine address.
|
||||
// Recipient validity via the shared, structure-based recognizers: a real encoding-checksum check
|
||||
// plus the actual DragonX address types — so a transcription error is never "Valid", and a valid
|
||||
// P2SH/multisig ('b…') recipient is no longer dropped by a hardcoded 'R'-only prefix filter.
|
||||
static bool IsValidShieldedAddr(const char* a) {
|
||||
return a[0] == 'z' && a[1] == 's' && strlen(a) > 60 && dragonx::util::isValidBech32(a);
|
||||
return a && dragonx::util::isShieldedAddress(a);
|
||||
}
|
||||
static bool IsValidTransparentAddr(const char* a) {
|
||||
return a[0] == 'R' && strlen(a) >= 34 && dragonx::util::isValidBase58Check(a);
|
||||
return a && dragonx::util::isTransparentAddress(a);
|
||||
}
|
||||
|
||||
static std::string timeAgo(int64_t timestamp) {
|
||||
@@ -1318,8 +1318,7 @@ void RenderSendTab(App* app)
|
||||
trimmed.erase(trimmed.begin());
|
||||
while (!trimmed.empty() && (trimmed.back() == ' ' || trimmed.back() == '\n' || trimmed.back() == '\r' || trimmed.back() == '\t'))
|
||||
trimmed.pop_back();
|
||||
bool looksValid = (trimmed.size() > 30 &&
|
||||
((trimmed[0] == 'z' && trimmed[1] == 's') || trimmed[0] == 'R'));
|
||||
bool looksValid = dragonx::util::isValidRecipientAddress(trimmed);
|
||||
if (looksValid && s_to_address[0] == '\0') {
|
||||
s_preview_text = trimmed;
|
||||
s_paste_previewing = true;
|
||||
|
||||
Reference in New Issue
Block a user