taler-typescript-core

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

commit 24abcbd76b859c56f1da4115802d2259ca5a8017
parent 686a65234b050d4f2806c7474cad39880664f3b4
Author: Florian Dold <florian@dold.me>
Date:   Wed,  7 May 2025 01:19:10 +0200

harness: fix more tests using old refresh

Diffstat:
Mpackages/taler-util/src/http-client/exchange-client.ts | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/dbless.ts | 79++++++++++++++++++++++++-------------------------------------------------------
2 files changed, 76 insertions(+), 55 deletions(-)

diff --git a/packages/taler-util/src/http-client/exchange-client.ts b/packages/taler-util/src/http-client/exchange-client.ts @@ -55,11 +55,14 @@ import { ExchangeGetContractResponse, ExchangeKeysResponse, ExchangeKycUploadFormRequest, + ExchangeMeltRequestV2, + ExchangeMeltResponse, ExchangeMergeConflictResponse, ExchangeMergeSuccessResponse, ExchangePurseDeposits, ExchangePurseMergeRequest, ExchangePurseStatus, + ExchangeRefreshRevealRequestV2, ExchangeReservePurseRequest, ExchangeTransferList, ExchangeVersionResponse, @@ -83,6 +86,7 @@ import { codecForExchangeConfig, codecForExchangeGetContractResponse, codecForExchangeKeysResponse, + codecForExchangeMeltResponse, codecForExchangeMergeConflictResponse, codecForExchangeMergeSuccessResponse, codecForExchangePurseStatus, @@ -1145,4 +1149,52 @@ export class TalerExchangeHttpClient2 { return opUnknownHttpFailure(resp); } } + + /** + * Request: POST /melt + * + * https://docs.taler.net/core/api-exchange.html#post--melt + */ + async postMelt(args: { + body: ExchangeMeltRequestV2; + }): Promise< + OperationOk<ExchangeMeltResponse> | OperationFail<HttpStatusCode.Forbidden> + > { + const url = new URL(`melt`, this.baseUrl); + const resp = await this.fetch(url, { + method: "POST", + body: args.body, + }); + // FIXME: Some documented cases are missing. + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForExchangeMeltResponse()); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownHttpFailure(resp); + } + } + + async postRevealMelt(args: { + body: ExchangeRefreshRevealRequestV2; + }): Promise< + | OperationOk<ExchangeWithdrawResponse> + | OperationFail<HttpStatusCode.Forbidden> + > { + const url = new URL(`reveal-melt`, this.baseUrl); + const resp = await this.fetch(url, { + method: "POST", + body: args.body, + }); + // FIXME: Some documented cases are missing. + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForExchangeWithdrawResponse()); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownHttpFailure(resp); + } + } } diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts @@ -35,8 +35,8 @@ import { EddsaPrivateKeyString, EddsaPublicKeyString, ExchangeBatchDepositRequest, - ExchangeMeltRequest, - ExchangeProtocolVersion, + ExchangeMeltRequestV2, + ExchangeRefreshRevealRequestV2, Logger, TalerCorebankApiClient, TalerExchangeHttpClient2, @@ -44,11 +44,10 @@ import { codecForAny, codecForBankWithdrawalOperationPostResponse, codecForBatchDepositSuccess, - codecForExchangeMeltResponse, - codecForExchangeRevealResponse, encodeCrock, getRandomBytes, hashWire, + j2s, parsePaytoUri, succeedOrThrow, } from "@gnu-taler/taler-util"; @@ -60,7 +59,6 @@ import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js"; import { DenominationRecord } from "./db.js"; import { isCandidateWithdrawableDenom } from "./denominations.js"; import { ExchangeInfo, downloadExchangeInfo } from "./exchanges.js"; -import { assembleRefreshRevealRequest } from "./refresh.js"; import { getBankStatusUrl, getBankWithdrawalInfo } from "./withdraw.js"; export { downloadExchangeInfo }; @@ -293,15 +291,14 @@ export async function refreshCoin(req: { newDenoms: DenominationRecord[]; }): Promise<void> { const { cryptoApi, oldCoin, http } = req; - const refreshSessionSeed = encodeCrock(getRandomBytes(32)); - const session = await cryptoApi.deriveRefreshSession({ - exchangeProtocolVersion: ExchangeProtocolVersion.V12, + const refreshSessionSeed = encodeCrock(getRandomBytes(64)); + const session = await cryptoApi.deriveRefreshSessionV2({ feeRefresh: Amounts.parseOrThrow(oldCoin.feeRefresh), kappa: 3, meltCoinDenomPubHash: oldCoin.denomPubHash, meltCoinPriv: oldCoin.coinPriv, meltCoinPub: oldCoin.coinPub, - sessionSecretSeed: refreshSessionSeed, + sessionPublicSeed: refreshSessionSeed, newCoinDenoms: req.newDenoms.map((x) => ({ count: 1, denomPub: x.denomPub, @@ -312,66 +309,38 @@ export async function refreshCoin(req: { meltCoinMaxAge: oldCoin.maxAge, }); - const meltReqBody: ExchangeMeltRequest = { - coin_pub: oldCoin.coinPub, + const meltReqBody: ExchangeMeltRequestV2 = { + old_coin_pub: oldCoin.coinPub, + old_denom_pub_h: oldCoin.denomPubHash, + old_denom_sig: oldCoin.denomSig, + // old_age_commitment_h: maybeAch, + refresh_seed: refreshSessionSeed, confirm_sig: session.confirmSig, - denom_pub_hash: oldCoin.denomPubHash, - denom_sig: oldCoin.denomSig, - rc: session.hash, + coin_evs: session.planchets.map((x) => x.map((y) => y.coinEv)), + denoms_h: req.newDenoms.map((x) => x.denomPubHash), value_with_fee: Amounts.stringify(session.meltValueWithFee), }; - logger.info("requesting melt"); - - const meltReqUrl = new URL( - `coins/${oldCoin.coinPub}/melt`, - oldCoin.exchangeBaseUrl, - ); + logger.info(`requesting melt: ${j2s(meltReqBody)}`); - logger.info("requesting melt done"); + const exchangeClient = new TalerExchangeHttpClient2(oldCoin.exchangeBaseUrl); - const meltHttpResp = await http.fetch(meltReqUrl.href, { - method: "POST", - body: meltReqBody, - }); - - const meltResponse = await readSuccessResponseJsonOrThrow( - meltHttpResp, - codecForExchangeMeltResponse(), + const meltResponse = succeedOrThrow( + await exchangeClient.postMelt({ body: meltReqBody }), ); const norevealIndex = meltResponse.noreveal_index; - const revealRequest = await assembleRefreshRevealRequest({ - cryptoApi, - derived: session, - newDenoms: req.newDenoms.map((x) => ({ - count: 1, - denomPubHash: x.denomPubHash, - })), - norevealIndex, - oldCoinPriv: oldCoin.coinPriv, - oldCoinPub: oldCoin.coinPub, - }); - - logger.info("requesting reveal"); - const reqUrl = new URL( - `refreshes/${session.hash}/reveal`, - oldCoin.exchangeBaseUrl, - ); + const revealRequest: ExchangeRefreshRevealRequestV2 = { + rc: session.hash, + signatures: session.signatures.filter((v, i) => i != norevealIndex), + // age_commitment: ... + }; - const revealResp = await http.fetch(reqUrl.href, { - method: "POST", - body: revealRequest, - }); + succeedOrThrow(await exchangeClient.postRevealMelt({ body: revealRequest })); logger.info("requesting reveal done"); - const reveal = await readSuccessResponseJsonOrThrow( - revealResp, - codecForExchangeRevealResponse(), - ); - // We could unblind here, but we only use this function to // benchmark the exchange. }