commit b4d1c980d688c68628b0293b2f313c28990cf17f
parent d5b68895e9545d3482eaf7ac5f38069dcb111a3a
Author: Florian Dold <florian@dold.me>
Date: Thu, 30 Jul 2026 19:17:04 +0200
util: add paytoFromTransferSubject helper
Diffstat:
2 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
@@ -15,22 +15,25 @@
*/
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, TalerError } from "./errors.js";
-import { TalerErrorCode } from "./taler-error-codes.js";
import { IbanString, parseIban, ParseIbanError } from "./iban.js";
-import { AmountString } from "./index.node.js";
+import { AmountString, j2s, Logger } from "./index.node.js";
import { Result, ResultError, ResultOk } from "./result.js";
+import { BitcoinSewgit } from "./segwit_addr.js";
import {
decodeCrock,
encodeCrock,
hashTruncate32,
stringToBytes,
} from "./taler-crypto.js";
+import { TalerErrorCode } from "./taler-error-codes.js";
+import { TransferSubject } from "./types-taler-prepared-transfer.js";
import { URLSearchParams } from "./url.js";
+const logger = new Logger("payto.ts");
+
export type PaytoString = string;
const PAYTO_PREFIX = "payto://";
@@ -1031,3 +1034,29 @@ function createSearchParams(paramList: [string, string][]): string {
.map(([key, value]) => `${rfc3986(key)}=${rfc3986(value)}`)
.join("&");
}
+
+export function paytoFromTransferSubject(
+ basePayto: string,
+ opt: TransferSubject,
+): string | undefined {
+ switch (opt.type) {
+ case "SIMPLE": {
+ return addPaytoQueryParams(basePayto, {
+ message: opt.subject,
+ amount: opt.credit_amount,
+ });
+ }
+ case "URI": {
+ return undefined;
+ }
+ case "CH_QR_BILL": {
+ return addPaytoQueryParams(basePayto, {
+ "ch-qrr": opt.qr_reference_number,
+ amount: opt.credit_amount,
+ });
+ }
+ default:
+ logger.warn(`Unsupported transfer subject: ${j2s(opt)}`);
+ return undefined;
+ }
+}
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -31,8 +31,9 @@ import {
ExchangeTosStatus,
ExchangeUpdateStatus,
ExchangeWireAccount,
+ HostPortPath,
Logger,
- ObservabilityEventType,
+ Paytos,
RefreshReason,
TalerError,
TalerErrorCode,
@@ -52,29 +53,28 @@ import {
assertUnreachable,
checkDbInvariant,
checkLogicInvariant,
+ decodeCrock,
durationMul,
getQrCodesForPayto,
j2s,
+ paytoFromTransferSubject,
succeedOrThrow,
- decodeCrock,
- HostPortPath,
- Paytos,
} from "@gnu-taler/taler-util";
import { HttpRequestOptions, HttpResponse } from "@gnu-taler/taler-util/http";
import {
DbPreciseTimestamp,
ExchangeEntryDbRecordStatus,
ExchangeEntryDbUpdateStatus,
- timestampPreciseToDb,
- WalletRetryInfo,
- WalletCoinHistory,
WalletCoin,
+ WalletCoinHistory,
WalletDepositGroup,
+ WalletExchangeEntry,
+ WalletPurchase,
WalletRecoupGroup,
WalletRefreshGroup,
+ WalletRetryInfo,
WalletWithdrawalGroup,
- WalletPurchase,
- WalletExchangeEntry,
+ timestampPreciseToDb,
} from "./db-common.js";
import {
PeerPullCreditRecord,
@@ -1223,10 +1223,8 @@ export async function prepareTransferOptionsRaw(
for (const opt of resp.subjects) {
switch (opt.type) {
case "SIMPLE": {
- const myPayto = addPaytoQueryParams(acct.payto_uri, {
- message: opt.subject,
- amount: transferAmount,
- });
+ const myPayto = paytoFromTransferSubject(acct.payto_uri, opt);
+ checkLogicInvariant(!!myPayto);
options.push({
type: "payto",
paytoUri: myPayto,
@@ -1242,10 +1240,8 @@ export async function prepareTransferOptionsRaw(
break;
}
case "CH_QR_BILL": {
- const myPayto = addPaytoQueryParams(acct.payto_uri, {
- "ch-qrr": opt.qr_reference_number,
- amount: transferAmount,
- });
+ const myPayto = paytoFromTransferSubject(acct.payto_uri, opt);
+ checkLogicInvariant(!!myPayto);
options.push({
type: "ch-qr-bill",
paytoUri: myPayto,