taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 25578cf199015938c49972be5bb4374dc9d5f1b6
parent f661cc9d5313f607776a9af634aae43722e94e7b
Author: Florian Dold <florian@dold.me>
Date:   Wed,  1 Jul 2026 19:47:33 +0200

fix prepared transfer API signature, fix test assertions

Diffstat:
Mpackages/taler-harness/src/integrationtests/test-kyc-form-bad-measure.ts | 3++-
Mpackages/taler-harness/src/integrationtests/test-withdrawal-shorten.ts | 14+++++---------
Mpackages/taler-wallet-core/src/common.ts | 25+++++++++++++++++++------
Mpackages/taler-wallet-core/src/crypto/cryptoImplementation.ts | 34++++++++++++++++------------------
Mpackages/taler-wallet-core/src/deposits.ts | 5+++--
Mpackages/taler-wallet-core/src/withdraw.ts | 5+++--
6 files changed, 48 insertions(+), 38 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-kyc-form-bad-measure.ts b/packages/taler-harness/src/integrationtests/test-kyc-form-bad-measure.ts @@ -144,8 +144,9 @@ export async function runKycFormBadMeasureTest(t: GlobalTestState) { ); console.log("resp status", uploadResp.status); + console.log(`resp body: ${j2s(uploadResp.json())}`); - t.assertDeepEqual(uploadResp.status, 500); + t.assertDeepEqual(uploadResp.status, 409); } runKycFormBadMeasureTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-shorten.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-shorten.ts @@ -70,8 +70,7 @@ export async function runWithdrawalShortenTest(t: GlobalTestState) { bank.corebankApiBaseUrl, ).href; - const prepBaseUrl = - bank.corebankApiBaseUrl + "/taler-prepared-transfer/"; + const prepBaseUrl = bank.corebankApiBaseUrl + "/taler-prepared-transfer/"; const exchangeBankAccount: HarnessExchangeBankAccount = { wireGatewayApiBaseUrl, @@ -115,13 +114,10 @@ export async function runWithdrawalShortenTest(t: GlobalTestState) { console.log(j2s(keys.accounts)); - const { walletClient, walletService } = await createWalletDaemonWithClient( - t, - { - name: "wallet", - persistent: true, - }, - ); + const { walletClient } = await createWalletDaemonWithClient(t, { + name: "wallet", + persistent: true, + }); await walletClient.call(WalletApiOperation.AddExchange, { exchangeBaseUrl: exchange.baseUrl, diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts @@ -51,10 +51,7 @@ import { assertUnreachable, checkDbInvariant, checkLogicInvariant, - decodeCrock, durationMul, - eddsaSign, - encodeCrock, getQrCodesForPayto, j2s, succeedOrThrow, @@ -1159,13 +1156,21 @@ export interface TransferOptionsRawResult { transferExpiry: TalerProtocolTimestamp; } -export async function getTransferOptionsRaw( +/** + * Get transfer options for withdrawals or + * KYC auth transfers. + * + * If necessary, register the target key with + * the prepared transfer service. + */ +export async function prepareTransferOptionsRaw( wex: WalletExecutionContext, req: { acct: ExchangeWireAccount; reservePub: string; reservePriv: string; transferAmount: AmountString; + isKyc: boolean; }, ): Promise<TransferOptionsRawResult> { const { acct, reservePub, reservePriv, transferAmount } = req; @@ -1194,14 +1199,22 @@ export async function getTransferOptionsRaw( acct.prepared_transfer_url, { httpClient: wex.http }, ); - const mySig = eddsaSign(decodeCrock(reservePub), decodeCrock(reservePriv)); + const mySig = await wex.cryptoApi.signPreparedTransferRegister({ + account_pub: reservePub, + alg: "EdDSA", + authorization_priv: reservePriv, + credit_account: acct.payto_uri, + credit_amount: transferAmount, + recurrent: false, + type: req.isKyc ? "kyc" : "reserve", + }); const resp = succeedOrThrow( await prepClient.register({ credit_account: acct.payto_uri, account_pub: reservePub, alg: "EdDSA", authorization_pub: reservePub, - authorization_sig: encodeCrock(mySig), + authorization_sig: mySig.sig, credit_amount: transferAmount, recurrent: false, type: "reserve", diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -2357,46 +2357,44 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { tci: TalerCryptoInterfaceR, req: SignPreparedTransferRegisterRequest, ): Promise<SignPreparedTransferRegisterResponse> { - - let b = buildSigPS( - TalerSignaturePurpose.WALLET_PREPARED_TRANSFER_REGISTER - ) - .put(hashTruncate32(stringToBytes(req.credit_account + "\0"))) - .put(bufferFromAmount(req.credit_amount)); + let b = buildSigPS(TalerSignaturePurpose.WALLET_PREPARED_TRANSFER_REGISTER) + .put(hashTruncate32(stringToBytes(req.credit_account + "\0"))) + .put(bufferFromAmount(req.credit_amount)); if (req.type == "reserve") { - b = b.put(bufferForUint32(1)); + b.put(bufferForUint32(1)); } else { - b = b.put(bufferForUint32(2)); + b.put(bufferForUint32(2)); } if (req.recurrent) { - b = b.put(bufferForUint16(2)); + b.put(bufferForUint16(2)); } else { - b = b.put(bufferForUint16(1)); + b.put(bufferForUint16(1)); } - b = b.put(bufferForUint16(1)).put(decodeCrock(req.account_pub)); + b.put(bufferForUint16(1)); + b.put(decodeCrock(req.account_pub)); return await tci.eddsaSign(tci, { msg: encodeCrock(b.build()), priv: req.authorization_priv, - }) + }); }, async signPreparedTransferUnregister( tci: TalerCryptoInterfaceR, req: SignPreparedTransferUnregisterRequest, ): Promise<SignPreparedTransferUnregisterResponse> { - const b = buildSigPS( - TalerSignaturePurpose.WALLET_PREPARED_TRANSFER_UNREGISTER + TalerSignaturePurpose.WALLET_PREPARED_TRANSFER_UNREGISTER, ) - .put(timestampRoundedToBuffer(req.timestamp)).build(); + .put(timestampRoundedToBuffer(req.timestamp)) + .build(); return await tci.eddsaSign(tci, { msg: encodeCrock(b), priv: req.authorization_priv, - }) - } -} + }); + }, +}; export interface EddsaSignRequest { msg: string; diff --git a/packages/taler-wallet-core/src/deposits.ts b/packages/taler-wallet-core/src/deposits.ts @@ -103,7 +103,7 @@ import { constructTaskIdentifier, genericWaitForState, getGenericRecordHandle, - getTransferOptionsRaw, + prepareTransferOptionsRaw, runWithClientCancellation, spendCoins, } from "./common.js"; @@ -1059,11 +1059,12 @@ async function getAuthTransferDetails( const exch = await fetchFreshExchange(wex, exchangeBaseUrl); for (const acct of exch.wireInfo.accounts) { - const optRes = await getTransferOptionsRaw(wex, { + const optRes = await prepareTransferOptionsRaw(wex, { acct, reservePriv: depositGroup.merchantPriv, reservePub: depositGroup.merchantPub, transferAmount: exch.tinyAmount, + isKyc: true, }); options.push(...optRes.transferOptions); if (!transferExpiry) { diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts @@ -128,9 +128,9 @@ import { genericWaitForState, genericWaitForStateVal, getGenericRecordHandle, - getTransferOptionsRaw, makeCoinAvailable, makeCoinsVisible, + prepareTransferOptionsRaw, requireExchangeTosAcceptedOrThrow, runWithClientCancellation, } from "./common.js"; @@ -4227,11 +4227,12 @@ async function fetchAccount( let options: TransferOption[] = []; let transferExpiry: TalerProtocolTimestamp | undefined = undefined; if (reservePub != null && reservePriv != null) { - const optRes = await getTransferOptionsRaw(wex, { + const optRes = await prepareTransferOptionsRaw(wex, { acct, reservePriv, reservePub, transferAmount, + isKyc: false, }); options = augmentTransferOptions(optRes.transferOptions); transferExpiry = optRes.transferExpiry;