commit 84976f692f0a6df7b302d69c872ac2d60b09ae2d
parent 9d4d47f4a417639d1f59b730af409d5eb1c8c561
Author: Florian Dold <dold@taler.net>
Date: Tue, 21 Jul 2026 10:55:15 +0200
util: validate bitcoin payto addresses as segwit addresses
The address was checked against bech32 only, so taproot and every later
witness version were rejected although the exchange accepts them.
Diffstat:
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
@@ -15,6 +15,7 @@
*/
import { BitcoinBech32 } from "./bech32.js";
+import { BitcoinSewgit } from "./segwit_addr.js";
import { generateFakeSegwitAddress } from "./bitcoin.js";
import { Codec, Context, DecodingError, renderContext } from "./codec.js";
import { assertUnreachable } from "./errors.js";
@@ -551,7 +552,10 @@ export namespace Paytos {
| {
targetType: PaytoType.Bitcoin;
pos: 0;
- error: ResultError<BitcoinBech32.BitcoinParseError>;
+ error: ResultError<
+ | BitcoinBech32.BitcoinParseError
+ | BitcoinSewgit.BitcoinSewgitParseError
+ >;
}
| {
targetType: PaytoType.Bitcoin;
@@ -687,10 +691,10 @@ export namespace Paytos {
}
const address = cs[0].toLowerCase();
- const btRes = BitcoinBech32.decode(
- address,
- BitcoinBech32.Encodings.BECH32,
- );
+ // Validate as a segwit address rather than as a bare bech32 string:
+ // the witness version decides which checksum constant applies, so
+ // pinning bech32 here rejects taproot and every later version.
+ const btRes = BitcoinSewgit.decode(address);
if (!opts.ignoreComponentError && Result.isError(btRes)) {
return Result.errorWithDetail(PaytoParseError.INVALID_TARGET_PATH, {
pos: 0 as const,