taler-typescript-core

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

commit 6bd8d385dcadd5df0a85e7a93a66ac764e959592
parent 77181b9c8ee2c824fc2c59ddd73d1fd4a65295b4
Author: Antoine A <>
Date:   Wed,  8 Apr 2026 20:57:01 +0200

common: update wire gateway version and improve prepared transfer test

Diffstat:
Mpackages/taler-harness/src/integrationtests/test-prepared-transfer.ts | 140++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mpackages/taler-util/src/http-client/bank-prepared.ts | 17++++++++++++++---
Mpackages/taler-util/src/http-client/bank-wire.ts | 149+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mpackages/taler-util/src/types-taler-common.ts | 4++++
Mpackages/taler-util/src/types-taler-prepared-transfer.ts | 110+++++++++++++++++++++++++++++++++----------------------------------------------
Mpackages/taler-util/src/types-taler-wire-gateway.ts | 130++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
6 files changed, 324 insertions(+), 226 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-prepared-transfer.ts b/packages/taler-harness/src/integrationtests/test-prepared-transfer.ts @@ -20,10 +20,11 @@ import { alternativeOrThrow, encodeCrock, - HttpStatusCode, succeedOrThrow, TalerCoreBankHttpClient, + TalerErrorCode, TalerPreparedTransferHttpClient, + TalerWireGatewayHttpClient, } from "@gnu-taler/taler-util"; import { BankService, @@ -33,6 +34,7 @@ import { setupDb, } from "../harness/harness.js"; import { createSyncCryptoApi } from "@gnu-taler/taler-wallet-core"; +import { AddMappedRequest } from "../../../taler-util/src/types-taler-wire-gateway.js"; export async function runPreparedTransferTest(t: GlobalTestState) { // Set up test environment @@ -55,47 +57,119 @@ export async function runPreparedTransferTest(t: GlobalTestState) { await bank.start(); const bankClient = new TalerCoreBankHttpClient(bank.corebankApiBaseUrl); - const preparedClient = new TalerPreparedTransferHttpClient(`${bank.corebankApiBaseUrl}accounts/${exchangeBankUsername}/taler-prepared-transfer/`,) + const preparedClient = new TalerPreparedTransferHttpClient( + `${bank.corebankApiBaseUrl}accounts/${exchangeBankUsername}/taler-prepared-transfer/`, + ); + const wireGatewayApiClient = new TalerWireGatewayHttpClient( + `${bank.corebankApiBaseUrl}accounts/${exchangeBankUsername}/taler-wire-gateway/`, + ); const bankAdminTok = await bank.getAdminTok(); + const merchant = succeedOrThrow( + await bankClient.createAccount(bankAdminTok, { + name: "merchant-default", + password: "merchant-default-pw", + username: "merchant-default", + }), + ); - succeedOrThrow(await bankClient.createAccount(bankAdminTok, { - name: receiverName, - password: exchangeBankPassword, - username: exchangeBankUsername, - is_taler_exchange: true, - payto_uri: exchangePaytoUri, - })); + succeedOrThrow( + await bankClient.createAccount(bankAdminTok, { + name: receiverName, + password: exchangeBankPassword, + username: exchangeBankUsername, + is_taler_exchange: true, + payto_uri: exchangePaytoUri, + }), + ); // Check config - succeedOrThrow(await preparedClient.getConfig()) + succeedOrThrow(await preparedClient.getConfig()); // Check registration - const keypair = await cryptoApi.createEddsaKeypair({}); - succeedOrThrow(await preparedClient.register({ - credit_amount: "TESTKUDOS:10", - type: "reserve", - alg: "EdDSA", - account_pub: keypair.pub, - authorization_pub: keypair.pub, - authorization_sig: (await cryptoApi.eddsaSign({ - msg: keypair.pub, - priv: keypair.priv - })).sig, - recurrent: false - })) + const auth_keypair = await cryptoApi.createEddsaKeypair({}); + const reserve_keypair = await cryptoApi.createEddsaKeypair({}); + succeedOrThrow( + await preparedClient.register({ + credit_amount: "TESTKUDOS:10", + type: "reserve", + alg: "EdDSA", + account_pub: reserve_keypair.pub, + authorization_pub: auth_keypair.pub, + authorization_sig: ( + await cryptoApi.eddsaSign({ + msg: reserve_keypair.pub, + priv: auth_keypair.priv, + }) + ).sig, + recurrent: false, + }), + ); // Check unregistration - const timestamp = new Date().toISOString() + const timestamp = new Date().toISOString(); const uint8 = new TextEncoder().encode(timestamp); - const res = await preparedClient.unregister({ - timestamp: timestamp, - authorization_pub: keypair.pub, - authorization_sig: (await cryptoApi.eddsaSign({ - msg: encodeCrock(uint8.buffer), - priv: keypair.priv - })).sig - }) - console.log(res) + succeedOrThrow( + await preparedClient.unregister({ + timestamp: timestamp, + authorization_pub: auth_keypair.pub, + authorization_sig: ( + await cryptoApi.eddsaSign({ + msg: encodeCrock(uint8.buffer), + priv: auth_keypair.priv, + }) + ).sig, + }), + ); + + // Check add mapped + alternativeOrThrow( + await wireGatewayApiClient.addMapped({ + body: { + authorization_pub: auth_keypair.pub, + amount: "TESTKUDOS:10", + debit_account: merchant.internal_payto_uri, + }, + auth: bank.getAdminAuth(), + }), + TalerErrorCode.BANK_TRANSFER_MAPPING_UNKNOWN, + ); + succeedOrThrow( + await preparedClient.register({ + credit_amount: "TESTKUDOS:10", + type: "reserve", + alg: "EdDSA", + account_pub: reserve_keypair.pub, + authorization_pub: auth_keypair.pub, + authorization_sig: ( + await cryptoApi.eddsaSign({ + msg: reserve_keypair.pub, + priv: auth_keypair.priv, + }) + ).sig, + recurrent: false, + }), + ); + succeedOrThrow( + await wireGatewayApiClient.addMapped({ + body: { + authorization_pub: auth_keypair.pub, + amount: "TESTKUDOS:10", + debit_account: merchant.internal_payto_uri, + }, + auth: bank.getAdminAuth(), + }), + ); + alternativeOrThrow( + await wireGatewayApiClient.addMapped({ + body: { + authorization_pub: auth_keypair.pub, + amount: "TESTKUDOS:10", + debit_account: merchant.internal_payto_uri, + }, + auth: bank.getAdminAuth(), + }), + TalerErrorCode.BANK_TRANSFER_MAPPING_REUSED, + ); } runPreparedTransferTest.suites = ["fakebank"]; diff --git a/packages/taler-util/src/http-client/bank-prepared.ts b/packages/taler-util/src/http-client/bank-prepared.ts @@ -24,8 +24,19 @@ import { opSuccessFromHttp, opUnknownHttpFailure, } from "../operation.js"; -import { carefullyParseConfig, codecForTalerErrorDetail, LibtoolVersion, opEmptySuccess, opKnownTalerFailure, TalerErrorCode, TalerPreparedTransferApi } from "../index.js"; -import { codecForPreparedTransferConfig, codecForRegistrationResponse } from "../types-taler-prepared-transfer.js"; +import { + carefullyParseConfig, + codecForTalerErrorDetail, + LibtoolVersion, + opEmptySuccess, + opKnownTalerFailure, + TalerErrorCode, + TalerPreparedTransferApi, +} from "../index.js"; +import { + codecForPreparedTransferConfig, + codecForRegistrationResponse, +} from "../types-taler-prepared-transfer.js"; export type TalerPreparedTransferResultByMethod< prop extends keyof TalerPreparedTransferHttpClient, @@ -131,7 +142,7 @@ export class TalerPreparedTransferHttpClient { case TalerErrorCode.BANK_BAD_SIGNATURE: return opKnownTalerFailure(details.code, details); default: - return opUnknownHttpFailure(resp, details); + return opKnownHttpFailure(resp.status, resp, details); } } default: diff --git a/packages/taler-util/src/http-client/bank-wire.ts b/packages/taler-util/src/http-client/bank-wire.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2022-2024 Taler Systems S.A. + (C) 2022-2024, 2026 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { HttpRequestLibrary, makeBasicAuthHeader } from "../http-common.js"; +import { HttpRequestLibrary, makeBasicAuthHeader, readTalerErrorResponse } from "../http-common.js"; import { HttpStatusCode } from "../http-status-codes.js"; import { createPlatformHttpLib } from "../http.js"; import { @@ -36,14 +36,18 @@ import { addLongPollingParam, addPaginationParams } from "./utils.js"; import { LongPollParams, PaginationParams } from "../types-taler-common.js"; import * as TalerWireGatewayApi from "../types-taler-wire-gateway.js"; -import { carefullyParseConfig, LibtoolVersion } from "../index.js"; +import { + carefullyParseConfig, + codecForTalerErrorDetail, + LibtoolVersion, + opKnownTalerFailure, + TalerErrorCode, +} from "../index.js"; -export type TalerWireGatewayResultByMethod< - prop extends keyof TalerWireGatewayHttpClient, -> = ResultByMethod<TalerWireGatewayHttpClient, prop>; -export type TalerWireGatewayErrorsByMethod< - prop extends keyof TalerWireGatewayHttpClient, -> = FailCasesByMethod<TalerWireGatewayHttpClient, prop>; +export type TalerWireGatewayResultByMethod<prop extends keyof TalerWireGatewayHttpClient> = + ResultByMethod<TalerWireGatewayHttpClient, prop>; +export type TalerWireGatewayErrorsByMethod<prop extends keyof TalerWireGatewayHttpClient> = + FailCasesByMethod<TalerWireGatewayHttpClient, prop>; export interface TalerWireGatewayAuth { username: string; @@ -59,7 +63,7 @@ export interface TalerWireGatewayAuth { */ export class TalerWireGatewayHttpClient { httpLib: HttpRequestLibrary; - public static readonly PROTOCOL_VERSION = "4:0:0"; + public static readonly PROTOCOL_VERSION = "5:0:1"; constructor( readonly baseUrl: string, @@ -111,26 +115,28 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, body: req.body, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForTransferResponse()); - //FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); - case HttpStatusCode.Conflict: - return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: { + const body = await readTalerErrorResponse(resp); + const details = codecForTalerErrorDetail().decode(body); + switch (details.code) { + case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED: + case TalerErrorCode.BANK_TRANSFER_WTID_REUSED: + return opKnownTalerFailure(details.code, details); + default: + return opKnownHttpFailure(resp.status, resp, details); + } + } default: return opUnknownHttpFailure(resp); } @@ -156,27 +162,19 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForBankWireTransferList()); - // FIXME: account should not be returned or make it optional case HttpStatusCode.NoContent: return opFixedSuccess({ transfers: [], debit_account: undefined, }); - // FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - // FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); default: @@ -193,21 +191,14 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForBankWireTransferList()); - //FIXME: account should not be returned or make it optional case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); default: @@ -229,27 +220,19 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForIncomingHistory()); - //FIXME: account should not be returned or make it optional case HttpStatusCode.NoContent: return opFixedSuccess({ incoming_transactions: [], credit_account: undefined, }); - //FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); default: @@ -271,27 +254,19 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "GET", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForOutgoingHistory()); - //FIXME: account should not be returned or make it optional case HttpStatusCode.NoContent: return opFixedSuccess({ outgoing_transactions: [], debit_account: undefined, }); - //FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); default: @@ -311,26 +286,27 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, body: req.body, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForAddIncomingResponse()); - //FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: - return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); - case HttpStatusCode.Conflict: - return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: { + const body = await readTalerErrorResponse(resp); + const details = codecForTalerErrorDetail().decode(body); + switch (details.code) { + case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT: + return opKnownTalerFailure(details.code, details); + default: + return opKnownHttpFailure(resp.status, resp, details); + } + } default: return opUnknownHttpFailure(resp); } @@ -348,24 +324,53 @@ export class TalerWireGatewayHttpClient { const resp = await this.httpLib.fetch(url.href, { method: "POST", headers: { - Authorization: makeBasicAuthHeader( - req.auth.username, - req.auth.password, - ), + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), }, body: req.body, }); switch (resp.status) { case HttpStatusCode.Ok: return opSuccessFromHttp(resp, codecForAddIncomingResponse()); - //FIXME: show more details in docs case HttpStatusCode.BadRequest: - return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.Unauthorized: + case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); - //FIXME: show more details in docs + default: + return opUnknownHttpFailure(resp); + } + } + + /** https://docs.taler.net/core/api-bank-wire.html#post--admin-add-mapped */ + async addMapped(req: { + body: TalerWireGatewayApi.AddMappedRequest; + auth: { username: string; password: string }; + }) { + const url = new URL(`admin/add-mapped`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBasicAuthHeader(req.auth.username, req.auth.password), + }, + body: req.body, + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForAddIncomingResponse()); + case HttpStatusCode.BadRequest: + case HttpStatusCode.Unauthorized: case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: { + const body = await readTalerErrorResponse(resp); + const details = codecForTalerErrorDetail().decode(body); + switch (details.code) { + case TalerErrorCode.BANK_TRANSFER_MAPPING_UNKNOWN: + case TalerErrorCode.BANK_TRANSFER_MAPPING_REUSED: + return opKnownTalerFailure(details.code, details); + default: + return opKnownHttpFailure(resp.status, resp, details); + } + } default: return opUnknownHttpFailure(resp); } diff --git a/packages/taler-util/src/types-taler-common.ts b/packages/taler-util/src/types-taler-common.ts @@ -87,6 +87,10 @@ export type EddsaPublicKey = EddsaPublicKeyString; // converted to Crockford Base32. export type EddsaPrivateKey = EddsaPrivateKeyString; +// EdDSA signatures are transmitted as 64-bytes base32 +// binary-encoded objects with just the R and S values (base32_ binary-only). +export type EddsaSignature = EddsaSignatureString; + // Edx25519 public keys are points on Curve25519 and represented using the // standard 256 bits Ed25519 compact format converted to Crockford // Base32. diff --git a/packages/taler-util/src/types-taler-prepared-transfer.ts b/packages/taler-util/src/types-taler-prepared-transfer.ts @@ -34,16 +34,13 @@ import { codecForTimestamp } from "./time.js"; import { AmountString, EddsaPublicKey, - EddsaSignatureString as EddsaSignature, + EddsaSignature, Timestamp, codecForEddsaPublicKey, - codecForEddsaSignature + codecForEddsaSignature, } from "./types-taler-common.js"; -export type SubjectFormat = - | "SIMPLE" - | "URI" - | "CH_QR_BILL"; +export type SubjectFormat = "SIMPLE" | "URI" | "CH_QR_BILL"; export interface PreparedTransferConfig { // Name of the API. @@ -90,10 +87,7 @@ export interface RegistrationRequest { } // Union discriminated by the "type" field. -export type TransferSubject = - | SimpleSubject - | UriSubject - | SwissQrBillSubject; +export type TransferSubject = SimpleSubject | UriSubject | SwissQrBillSubject; export interface SimpleSubject { // Subject for system accepting large subjects @@ -149,13 +143,12 @@ export interface Unregistration { authorization_sig: EddsaSignature; } -export const codeForSubjectFormat = - (): Codec<TalerPreparedTransferApi.SubjectFormat> => - codecForEither( - codecForConstString("SIMPLE"), - codecForConstString("URI"), - codecForConstString("CH_QR_BILL"), - ); +export const codeForSubjectFormat = (): Codec<TalerPreparedTransferApi.SubjectFormat> => + codecForEither( + codecForConstString("SIMPLE"), + codecForConstString("URI"), + codecForConstString("CH_QR_BILL"), + ); export const codecForPreparedTransferConfig = (): Codec<TalerPreparedTransferApi.PreparedTransferConfig> => @@ -171,51 +164,42 @@ export const codecForRegistrationRequest = (): Codec<TalerPreparedTransferApi.RegistrationRequest> => buildCodecForObject<TalerPreparedTransferApi.RegistrationRequest>() .property("credit_amount", codecForAmountString()) - .property("type", codecForEither( - codecForConstString("reserve"), - codecForConstString("kyc"), - )) - .property("alg", codecForEither( - codecForConstString("EdDSA") - )) + .property("type", codecForEither(codecForConstString("reserve"), codecForConstString("kyc"))) + .property("alg", codecForEither(codecForConstString("EdDSA"))) .property("account_pub", codecForEddsaPublicKey()) .property("authorization_pub", codecForEddsaPublicKey()) .property("authorization_sig", codecForEddsaSignature()) .property("recurrent", codecForBoolean()) .build("TalerWireGatewayApi.RegistrationRequest"); -export const codecForTransferSubject = - (): Codec<TalerPreparedTransferApi.TransferSubject> => - buildCodecForUnion<TalerPreparedTransferApi.TransferSubject>() - .discriminateOn("type") - .alternative("SIMPLE", codecForSimpleSubject()) - .alternative("URI", codecForUriSubject()) - .alternative("CH_QR_BILL", codecForSwissQrBillSubject()) - .build("TalerPreparedTransferApi.TransferSubject"); - -export const codecForSimpleSubject = - (): Codec<TalerPreparedTransferApi.SimpleSubject> => - buildCodecForObject<TalerPreparedTransferApi.SimpleSubject>() - .property("type", codecForConstString("SIMPLE")) - .property("credit_amount", codecForAmountString()) - .property("subject", codecForString()) - .build("TalerPreparedTransferApi.SimpleSubject"); - -export const codecForUriSubject = - (): Codec<TalerPreparedTransferApi.UriSubject> => - buildCodecForObject<TalerPreparedTransferApi.UriSubject>() - .property("type", codecForConstString("URI")) - .property("credit_amount", codecForAmountString()) - .property("uri", codecForStringURL()) - .build("TalerPreparedTransferApi.UriSubject"); - -export const codecForSwissQrBillSubject = - (): Codec<TalerPreparedTransferApi.SwissQrBillSubject> => - buildCodecForObject<TalerPreparedTransferApi.SwissQrBillSubject>() - .property("type", codecForConstString("CH_QR_BILL")) - .property("credit_amount", codecForAmountString()) - .property("qr_reference_number", codecForString()) - .build("TalerPreparedTransferApi.SwissQrBillSubject"); +export const codecForTransferSubject = (): Codec<TalerPreparedTransferApi.TransferSubject> => + buildCodecForUnion<TalerPreparedTransferApi.TransferSubject>() + .discriminateOn("type") + .alternative("SIMPLE", codecForSimpleSubject()) + .alternative("URI", codecForUriSubject()) + .alternative("CH_QR_BILL", codecForSwissQrBillSubject()) + .build("TalerPreparedTransferApi.TransferSubject"); + +export const codecForSimpleSubject = (): Codec<TalerPreparedTransferApi.SimpleSubject> => + buildCodecForObject<TalerPreparedTransferApi.SimpleSubject>() + .property("type", codecForConstString("SIMPLE")) + .property("credit_amount", codecForAmountString()) + .property("subject", codecForString()) + .build("TalerPreparedTransferApi.SimpleSubject"); + +export const codecForUriSubject = (): Codec<TalerPreparedTransferApi.UriSubject> => + buildCodecForObject<TalerPreparedTransferApi.UriSubject>() + .property("type", codecForConstString("URI")) + .property("credit_amount", codecForAmountString()) + .property("uri", codecForStringURL()) + .build("TalerPreparedTransferApi.UriSubject"); + +export const codecForSwissQrBillSubject = (): Codec<TalerPreparedTransferApi.SwissQrBillSubject> => + buildCodecForObject<TalerPreparedTransferApi.SwissQrBillSubject>() + .property("type", codecForConstString("CH_QR_BILL")) + .property("credit_amount", codecForAmountString()) + .property("qr_reference_number", codecForString()) + .build("TalerPreparedTransferApi.SwissQrBillSubject"); export const codecForRegistrationResponse = (): Codec<TalerPreparedTransferApi.RegistrationResponse> => @@ -224,10 +208,9 @@ export const codecForRegistrationResponse = .property("expiration", codecForTimestamp) .build("TalerWireGatewayApi.RegistrationResponse"); -export const codecForUnregistration = - (): Codec<TalerPreparedTransferApi.Unregistration> => - buildCodecForObject<TalerPreparedTransferApi.Unregistration>() - .property("timestamp", codecForString()) - .property("authorization_pub", codecForEddsaPublicKey()) - .property("authorization_sig", codecForEddsaSignature()) - .build("TalerPreparedTransferApi.Unregistration"); -\ No newline at end of file +export const codecForUnregistration = (): Codec<TalerPreparedTransferApi.Unregistration> => + buildCodecForObject<TalerPreparedTransferApi.Unregistration>() + .property("timestamp", codecForString()) + .property("authorization_pub", codecForEddsaPublicKey()) + .property("authorization_sig", codecForEddsaSignature()) + .build("TalerPreparedTransferApi.Unregistration"); diff --git a/packages/taler-util/src/types-taler-wire-gateway.ts b/packages/taler-util/src/types-taler-wire-gateway.ts @@ -29,7 +29,7 @@ import { codecForStringURL, codecOptional, } from "./codec.js"; -import { TalerWireGatewayApi } from "./index.js"; +import { codecForEddsaSignature, EddsaSignature, TalerWireGatewayApi } from "./index.js"; import { codecForAmountString } from "./amounts.js"; import { PaytoString, codecForPaytoString } from "./payto.js"; import { codecForTimestamp } from "./time.js"; @@ -136,6 +136,12 @@ export interface IncomingReserveTransaction { // The reserve public key extracted from the transaction details. reserve_pub: EddsaPublicKey; + + // The authorization public key used for mapping + authorization_pub?: EddsaPublicKey; + + // Signature of the account public key using the authorization private key + authorization_sig?: EddsaSignature; } export interface IncomingKycAuthTransaction { @@ -155,6 +161,12 @@ export interface IncomingKycAuthTransaction { // The reserve public key extracted from the transaction details. account_pub: EddsaPublicKey; + + // The authorization public key used for mapping + authorization_pub?: EddsaPublicKey; + + // Signature of the account public key using the authorization private key + authorization_sig?: EddsaSignature; } export interface IncomingWadTransaction { @@ -177,6 +189,12 @@ export interface IncomingWadTransaction { // The reserve public key extracted from the transaction details. wad_id: WadId; + + // The authorization public key used for mapping + authorization_pub?: EddsaPublicKey; + + // Signature of the account public key using the authorization private key + authorization_sig?: EddsaSignature; } export interface OutgoingHistory { @@ -242,6 +260,20 @@ export interface AddKycauthRequest { debit_account: string; } +export interface AddMappedRequest { + // Amount to transfer. + amount: AmountString; + + // Authorization public key used for registration. + authorization_pub: EddsaPublicKey; + + // Account (as full payto URI) that makes the wire transfer to the exchange. + // Usually this account must be created by the test harness before this + // API is used. An exception is the "fakebank", where any debit account + // can be specified, as it is automatically created. + debit_account: string; +} + export interface AddIncomingResponse { // Timestamp that indicates when the wire transfer will be executed. // In cases where the wire transfer gateway is unable to know when @@ -267,11 +299,7 @@ export interface BankWireTransferList { debit_account: string; } -export type WireTransferStatus = - | "pending" - | "transient_failure" - | "permanent_failure" - | "success"; +export type WireTransferStatus = "pending" | "transient_failure" | "permanent_failure" | "success"; export interface BankWireTransferListStatus { // Opaque ID of the wire transfer initiation performed by the bank. @@ -337,32 +365,26 @@ export interface BankWireTransferStatus { timestamp: Timestamp; } -export const codecForWireConfigResponse = - (): Codec<TalerWireGatewayApi.WireConfig> => - buildCodecForObject<TalerWireGatewayApi.WireConfig>() - .property("currency", codecForString()) - .property("implementation", codecForString()) - .property("name", codecForConstString("taler-wire-gateway")) - .property("support_account_check", codecForBoolean()) - .property("version", codecForString()) - .build("TalerWireGatewayApi.WireConfig"); - -export const codecForTransferResponse = - (): Codec<TalerWireGatewayApi.TransferResponse> => - buildCodecForObject<TalerWireGatewayApi.TransferResponse>() - .property("row_id", codecForNumber()) - .property("timestamp", codecForTimestamp) - .build("TalerWireGatewayApi.TransferResponse"); - -export const codecForIncomingHistory = - (): Codec<TalerWireGatewayApi.IncomingHistory> => - buildCodecForObject<TalerWireGatewayApi.IncomingHistory>() - .property("credit_account", codecForPaytoString()) - .property( - "incoming_transactions", - codecForList(codecForIncomingBankTransaction()), - ) - .build("TalerWireGatewayApi.IncomingHistory"); +export const codecForWireConfigResponse = (): Codec<TalerWireGatewayApi.WireConfig> => + buildCodecForObject<TalerWireGatewayApi.WireConfig>() + .property("currency", codecForString()) + .property("implementation", codecForString()) + .property("name", codecForConstString("taler-wire-gateway")) + .property("support_account_check", codecForBoolean()) + .property("version", codecForString()) + .build("TalerWireGatewayApi.WireConfig"); + +export const codecForTransferResponse = (): Codec<TalerWireGatewayApi.TransferResponse> => + buildCodecForObject<TalerWireGatewayApi.TransferResponse>() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.TransferResponse"); + +export const codecForIncomingHistory = (): Codec<TalerWireGatewayApi.IncomingHistory> => + buildCodecForObject<TalerWireGatewayApi.IncomingHistory>() + .property("credit_account", codecForPaytoString()) + .property("incoming_transactions", codecForList(codecForIncomingBankTransaction())) + .build("TalerWireGatewayApi.IncomingHistory"); export const codecForIncomingBankTransaction = (): Codec<TalerWireGatewayApi.IncomingBankTransaction> => @@ -382,6 +404,8 @@ export const codecForIncomingReserveTransaction = .property("reserve_pub", codecForEddsaPublicKey()) .property("row_id", codecForNumber()) .property("type", codecForConstString("RESERVE")) + .property("authorization_pub", codecOptional(codecForEddsaPublicKey())) + .property("authorization_sig", codecOptional(codecForEddsaSignature())) .build("TalerWireGatewayApi.IncomingReserveTransaction"); export const codecForIncomingKycAuthTransaction = @@ -393,6 +417,8 @@ export const codecForIncomingKycAuthTransaction = .property("account_pub", codecForEddsaPublicKey()) .property("row_id", codecForNumber()) .property("type", codecForConstString("KYCAUTH")) + .property("authorization_pub", codecOptional(codecForEddsaPublicKey())) + .property("authorization_sig", codecOptional(codecForEddsaSignature())) .build("TalerWireGatewayApi.IncomingKycAuthTransaction"); export const codecForIncomingWadTransaction = @@ -405,17 +431,15 @@ export const codecForIncomingWadTransaction = .property("row_id", codecForNumber()) .property("type", codecForConstString("WAD")) .property("wad_id", codecForString()) + .property("authorization_pub", codecOptional(codecForEddsaPublicKey())) + .property("authorization_sig", codecOptional(codecForEddsaSignature())) .build("TalerWireGatewayApi.IncomingWadTransaction"); -export const codecForOutgoingHistory = - (): Codec<TalerWireGatewayApi.OutgoingHistory> => - buildCodecForObject<TalerWireGatewayApi.OutgoingHistory>() - .property("debit_account", codecForPaytoString()) - .property( - "outgoing_transactions", - codecForList(codecForOutgoingBankTransaction()), - ) - .build("TalerWireGatewayApi.OutgoingHistory"); +export const codecForOutgoingHistory = (): Codec<TalerWireGatewayApi.OutgoingHistory> => + buildCodecForObject<TalerWireGatewayApi.OutgoingHistory>() + .property("debit_account", codecForPaytoString()) + .property("outgoing_transactions", codecForList(codecForOutgoingBankTransaction())) + .build("TalerWireGatewayApi.OutgoingHistory"); export const codecForOutgoingBankTransaction = (): Codec<TalerWireGatewayApi.OutgoingBankTransaction> => @@ -428,19 +452,17 @@ export const codecForOutgoingBankTransaction = .property("exchange_base_url", codecForString()) .build("TalerWireGatewayApi.OutgoingBankTransaction"); -export const codecForAddIncomingResponse = - (): Codec<TalerWireGatewayApi.AddIncomingResponse> => - buildCodecForObject<TalerWireGatewayApi.AddIncomingResponse>() - .property("row_id", codecForNumber()) - .property("timestamp", codecForTimestamp) - .build("TalerWireGatewayApi.AddIncomingResponse"); - -export const codecForBankWireTransferList = - (): Codec<TalerWireGatewayApi.BankWireTransferList> => - buildCodecForObject<TalerWireGatewayApi.BankWireTransferList>() - .property("debit_account", codecForPaytoString()) - .property("transfers", codecForList(codecForBankWireTransferListStatus())) - .build("TalerWireGatewayApi.BankWireTransferList"); +export const codecForAddIncomingResponse = (): Codec<TalerWireGatewayApi.AddIncomingResponse> => + buildCodecForObject<TalerWireGatewayApi.AddIncomingResponse>() + .property("row_id", codecForNumber()) + .property("timestamp", codecForTimestamp) + .build("TalerWireGatewayApi.AddIncomingResponse"); + +export const codecForBankWireTransferList = (): Codec<TalerWireGatewayApi.BankWireTransferList> => + buildCodecForObject<TalerWireGatewayApi.BankWireTransferList>() + .property("debit_account", codecForPaytoString()) + .property("transfers", codecForList(codecForBankWireTransferListStatus())) + .build("TalerWireGatewayApi.BankWireTransferList"); export const codecForBankWireTransferStatus = (): Codec<TalerWireGatewayApi.BankWireTransferStatus> =>