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:
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> =>