summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2023-11-22 15:20:10 +0100
committerFlorian Dold <florian@dold.me>2023-11-22 17:08:15 +0100
commitbd37a0b04123d734e1e3fae105f0d9c24279629f (patch)
tree31f03c2acd3c1f123f8762391456b1aa22df9803
parent32182fb1b912e1136ba933c4a4f204e6e2f33de2 (diff)
downloadwallet-core-bd37a0b04123d734e1e3fae105f0d9c24279629f.tar.gz
wallet-core-bd37a0b04123d734e1e3fae105f0d9c24279629f.tar.bz2
wallet-core-bd37a0b04123d734e1e3fae105f0d9c24279629f.zip
wallet-core: implement and test currency conversion withdrawals
-rw-r--r--packages/taler-harness/src/harness/harness.ts39
-rw-r--r--packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts34
-rw-r--r--packages/taler-util/src/http-client/types.ts534
-rw-r--r--packages/taler-util/src/taler-types.ts41
-rw-r--r--packages/taler-util/src/transactions-types.ts5
-rw-r--r--packages/taler-util/src/wallet-types.ts24
-rw-r--r--packages/taler-wallet-core/src/crypto/cryptoImplementation.ts2
-rw-r--r--packages/taler-wallet-core/src/db.ts7
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts129
-rw-r--r--packages/taler-wallet-core/src/wallet.ts1
11 files changed, 474 insertions, 343 deletions
diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts
index 37e0b02a7..242bf2207 100644
--- a/packages/taler-harness/src/harness/harness.ts
+++ b/packages/taler-harness/src/harness/harness.ts
@@ -928,6 +928,8 @@ export class ExchangeService implements ExchangeServiceInterface {
private currentTimetravelOffsetMs: number | undefined;
+ private exchangeBankAccounts: HarnessExchangeBankAccount[] = [];
+
setTimetravel(t: number | undefined): void {
if (this.isRunning()) {
throw Error("can't set time travel while the exchange is running");
@@ -1132,6 +1134,7 @@ export class ExchangeService implements ExchangeServiceInterface {
localName: string,
exchangeBankAccount: HarnessExchangeBankAccount,
): Promise<void> {
+ this.exchangeBankAccounts.push(exchangeBankAccount);
const config = Configuration.load(this.configFilename);
config.setString(
`exchange-account-${localName}`,
@@ -1277,32 +1280,32 @@ export class ExchangeService implements ExchangeServiceInterface {
["-c", this.configFilename, "download", "sign", "upload"],
);
- const accounts: string[] = [];
const accountTargetTypes: Set<string> = new Set();
- const config = Configuration.load(this.configFilename);
- for (const sectionName of config.getSectionNames()) {
- if (sectionName.startsWith("EXCHANGE-ACCOUNT-")) {
- const paytoUri = config.getString(sectionName, "payto_uri").required();
- const p = parsePaytoUri(paytoUri);
- if (!p) {
- throw Error(`invalid payto uri in exchange config: ${paytoUri}`);
- }
- accountTargetTypes.add(p?.targetType);
- accounts.push(paytoUri);
+ for (const acct of this.exchangeBankAccounts) {
+ const paytoUri = acct.accountPaytoUri;
+ const p = parsePaytoUri(paytoUri);
+ if (!p) {
+ throw Error(`invalid payto uri in exchange config: ${paytoUri}`);
+ }
+ accountTargetTypes.add(p?.targetType);
+ const optArgs: string[] = [];
+ if (acct.conversionUrl != null) {
+ optArgs.push("conversion-url", acct.conversionUrl);
}
- }
-
- const accountsDescription = accounts.map((acc) => ` * ${acc}`).join("\n");
- logger.info("configuring bank accounts:");
- logger.info(accountsDescription);
- for (const acc of accounts) {
await runCommand(
this.globalState,
"exchange-offline",
"taler-exchange-offline",
- ["-c", this.configFilename, "enable-account", acc, "upload"],
+ [
+ "-c",
+ this.configFilename,
+ "enable-account",
+ paytoUri,
+ ...optArgs,
+ "upload",
+ ],
);
}
diff --git a/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts b/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts
index 2a9dd5800..6fc403be4 100644
--- a/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts
+++ b/packages/taler-harness/src/integrationtests/test-withdrawal-conversion.ts
@@ -23,7 +23,9 @@ import {
Duration,
Logger,
TalerCorebankApiClient,
+ TransactionType,
WireGatewayApiClient,
+ WithdrawalType,
j2s,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
@@ -184,16 +186,21 @@ export async function runWithdrawalConversionTest(t: GlobalTestState) {
exchangeBaseUrl: exchange.baseUrl,
});
- const infoRes = walletClient.call(
+ const infoRes = await walletClient.call(
WalletApiOperation.GetWithdrawalDetailsForAmount,
{
exchangeBaseUrl: exchange.baseUrl,
- amount: "EXTCOIN:20" as AmountString,
+ amount: "TESTKUDOS:20" as AmountString,
},
);
console.log(`withdrawal details: ${j2s(infoRes)}`);
+ t.assertAmountEquals(
+ infoRes.withdrawalAccountList[0].transferAmount,
+ "FOO:123",
+ );
+
const tStart = AbsoluteTime.now();
logger.info("starting AcceptManualWithdrawal request");
@@ -210,6 +217,29 @@ export async function runWithdrawalConversionTest(t: GlobalTestState) {
logger.info("AcceptManualWithdrawal finished");
logger.info(`result: ${j2s(wres)}`);
+ t.assertAmountEquals(
+ wres.withdrawalAccountsList[0].transferAmount,
+ "FOO:123",
+ );
+
+ const txInfo = await walletClient.call(
+ WalletApiOperation.GetTransactionById,
+ {
+ transactionId: wres.transactionId,
+ },
+ );
+
+ t.assertDeepEqual(txInfo.type, TransactionType.Withdrawal);
+ t.assertDeepEqual(
+ txInfo.withdrawalDetails.type,
+ WithdrawalType.ManualTransfer,
+ );
+ t.assertTrue(!!txInfo.withdrawalDetails.exchangeCreditAccounts);
+ t.assertDeepEqual(
+ txInfo.withdrawalDetails.exchangeCreditAccounts[0].transferAmount,
+ "FOO:123",
+ );
+
// Check that the request did not go into long-polling.
const duration = AbsoluteTime.difference(tStart, AbsoluteTime.now());
if (typeof duration.d_ms !== "number" || duration.d_ms > 5 * 1000) {
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index d50a0ea90..3ef0ff76c 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -1,20 +1,32 @@
import { codecForAmountString } from "../amounts.js";
-import { Codec, buildCodecForObject, buildCodecForUnion, codecForAny, codecForBoolean, codecForConstString, codecForEither, codecForList, codecForMap, codecForNumber, codecForString, codecOptional } from "../codec.js";
+import {
+ Codec,
+ buildCodecForObject,
+ buildCodecForUnion,
+ codecForAny,
+ codecForBoolean,
+ codecForConstString,
+ codecForEither,
+ codecForList,
+ codecForMap,
+ codecForNumber,
+ codecForString,
+ codecOptional,
+} from "../codec.js";
import { PaytoString, codecForPaytoString } from "../payto.js";
import { AmountString } from "../taler-types.js";
import { TalerActionString, codecForTalerActionString } from "../taleruri.js";
import { codecForTimestamp } from "../time.js";
-
export type UserAndPassword = {
- username: string,
- password: string,
-}
+ username: string;
+ password: string;
+};
export type UserAndToken = {
- username: string,
- token: AccessToken,
-}
+ username: string;
+ token: AccessToken;
+};
declare const opaque_OfficerAccount: unique symbol;
export type LockedAccount = string & { [opaque_OfficerAccount]: true };
@@ -25,32 +37,30 @@ export type OfficerId = string & { [opaque_OfficerId]: true };
declare const opaque_OfficerSigningKey: unique symbol;
export type SigningKey = Uint8Array & { [opaque_OfficerSigningKey]: true };
-
export interface OfficerAccount {
id: OfficerId;
signingKey: SigningKey;
}
-
export type PaginationParams = {
/**
* row identifier as the starting point of the query
*/
- offset?: string,
+ offset?: string;
/**
* max number of element in the result response
* always greater than 0
*/
- limit?: number,
+ limit?: number;
/**
* milliseconds the server should wait for at least one result to be shown
*/
- timoutMs?: number,
+ timoutMs?: number;
/**
* order
*/
- order: "asc" | "dec"
-}
+ order: "asc" | "dec";
+};
///
/// HASH
@@ -148,7 +158,6 @@ type SafeUint64 = number;
// Invalid strings will be rejected by the wallet.
type ImageDataUrl = string;
-
type WadId = string;
interface Timestamp {
@@ -166,8 +175,8 @@ interface RelativeTime {
}
export interface LoginToken {
- token: AccessToken,
- expiration: Timestamp,
+ token: AccessToken;
+ expiration: Timestamp;
}
declare const __ac_token: unique symbol;
@@ -175,14 +184,12 @@ export type AccessToken = string & {
[__ac_token]: true;
};
-
declare const __officer_signature: unique symbol;
export type OfficerSignature = string & {
[__officer_signature]: true;
};
export namespace TalerAuthentication {
-
export interface TokenRequest {
// Service-defined scope for the token.
// Typical scopes would be "readonly" or "readwrite".
@@ -213,7 +220,6 @@ export namespace TalerAuthentication {
// DD51 https://docs.taler.net/design-documents/051-fractional-digits.html
export interface CurrencySpecification {
-
// Name of the currency.
name: string;
@@ -240,7 +246,7 @@ export const codecForTokenSuccessResponse =
buildCodecForObject<TalerAuthentication.TokenSuccessResponse>()
.property("access_token", codecForAccessToken())
.property("expiration", codecForTimestamp)
- .build("TalerAuthentication.TokenSuccessResponse")
+ .build("TalerAuthentication.TokenSuccessResponse");
export const codecForCurrencySpecificiation =
(): Codec<CurrencySpecification> =>
@@ -250,27 +256,26 @@ export const codecForCurrencySpecificiation =
.property("num_fractional_normal_digits", codecForNumber())
.property("num_fractional_trailing_zero_digits", codecForNumber())
.property("alt_unit_names", codecForMap(codecForString()))
- .build("CurrencySpecification")
+ .build("CurrencySpecification");
export const codecForIntegrationBankConfig =
(): Codec<TalerCorebankApi.IntegrationConfig> =>
buildCodecForObject<TalerCorebankApi.IntegrationConfig>()
.property("name", codecForConstString("taler-bank-integration"))
.property("version", codecForString())
- .property("currency", codecForCurrencySpecificiation())
- .build("TalerCorebankApi.IntegrationConfig")
-
-export const codecForCoreBankConfig =
- (): Codec<TalerCorebankApi.Config> =>
- buildCodecForObject<TalerCorebankApi.Config>()
- .property("name", codecForConstString("libeufin-bank"))
- .property("version", codecForString())
- .property("allow_conversion", codecForBoolean())
- .property("allow_deletions", codecForBoolean())
- .property("allow_registrations", codecForBoolean())
- .property("currency_specification", codecForCurrencySpecificiation())
.property("currency", codecForString())
- .build("TalerCorebankApi.Config")
+ .build("TalerCorebankApi.IntegrationConfig");
+
+export const codecForCoreBankConfig = (): Codec<TalerCorebankApi.Config> =>
+ buildCodecForObject<TalerCorebankApi.Config>()
+ .property("name", codecForConstString("libeufin-bank"))
+ .property("version", codecForString())
+ .property("allow_conversion", codecForBoolean())
+ .property("allow_deletions", codecForBoolean())
+ .property("allow_registrations", codecForBoolean())
+ .property("currency_specification", codecForCurrencySpecificiation())
+ .property("currency", codecForString())
+ .build("TalerCorebankApi.Config");
export const codecForMerchantConfig =
(): Codec<TalerMerchantApi.VersionResponse> =>
@@ -279,7 +284,7 @@ export const codecForMerchantConfig =
.property("currency", codecForString())
.property("version", codecForString())
.property("currencies", codecForMap(codecForCurrencySpecificiation()))
- .build("TalerMerchantApi.VersionResponse")
+ .build("TalerMerchantApi.VersionResponse");
export const codecForExchangeConfig =
(): Codec<TalerExchangeApi.ExchangeVersionResponse> =>
@@ -289,27 +294,32 @@ export const codecForExchangeConfig =
.property("currency", codecForString())
.property("currency_specification", codecForCurrencySpecificiation())
.property("supported_kyc_requirements", codecForList(codecForString()))
- .build("TalerExchangeApi.ExchangeVersionResponse")
+ .build("TalerExchangeApi.ExchangeVersionResponse");
const codecForBalance = (): Codec<TalerCorebankApi.Balance> =>
buildCodecForObject<TalerCorebankApi.Balance>()
.property("amount", codecForAmountString())
- .property("credit_debit_indicator", codecForEither(codecForConstString("credit"), codecForConstString("debit")))
- .build("TalerCorebankApi.Balance")
+ .property(
+ "credit_debit_indicator",
+ codecForEither(
+ codecForConstString("credit"),
+ codecForConstString("debit"),
+ ),
+ )
+ .build("TalerCorebankApi.Balance");
const codecForPublicAccount = (): Codec<TalerCorebankApi.PublicAccount> =>
buildCodecForObject<TalerCorebankApi.PublicAccount>()
.property("account_name", codecForString())
.property("balance", codecForBalance())
.property("payto_uri", codecForPaytoString())
- .build("TalerCorebankApi.PublicAccount")
+ .build("TalerCorebankApi.PublicAccount");
export const codecForPublicAccountsResponse =
(): Codec<TalerCorebankApi.PublicAccountsResponse> =>
buildCodecForObject<TalerCorebankApi.PublicAccountsResponse>()
.property("public_accounts", codecForList(codecForPublicAccount()))
- .build("TalerCorebankApi.PublicAccountsResponse")
-
+ .build("TalerCorebankApi.PublicAccountsResponse");
export const codecForAccountMinimalData =
(): Codec<TalerCorebankApi.AccountMinimalData> =>
@@ -318,37 +328,38 @@ export const codecForAccountMinimalData =
.property("debit_threshold", codecForAmountString())
.property("name", codecForString())
.property("username", codecForString())
- .build("TalerCorebankApi.AccountMinimalData")
+ .build("TalerCorebankApi.AccountMinimalData");
export const codecForListBankAccountsResponse =
(): Codec<TalerCorebankApi.ListBankAccountsResponse> =>
buildCodecForObject<TalerCorebankApi.ListBankAccountsResponse>()
.property("accounts", codecForList(codecForAccountMinimalData()))
- .build("TalerCorebankApi.ListBankAccountsResponse")
-
-export const codecForAccountData =
- (): Codec<TalerCorebankApi.AccountData> =>
- buildCodecForObject<TalerCorebankApi.AccountData>()
- .property("name", codecForString())
- .property("balance", codecForBalance())
- .property("payto_uri", codecForPaytoString())
- .property("debit_threshold", codecForAmountString())
- .property("contact_data", codecOptional(codecForChallengeContactData()))
- .property("cashout_payto_uri", codecOptional(codecForPaytoString()))
- .build("TalerCorebankApi.AccountData")
+ .build("TalerCorebankApi.ListBankAccountsResponse");
+export const codecForAccountData = (): Codec<TalerCorebankApi.AccountData> =>
+ buildCodecForObject<TalerCorebankApi.AccountData>()
+ .property("name", codecForString())
+ .property("balance", codecForBalance())
+ .property("payto_uri", codecForPaytoString())
+ .property("debit_threshold", codecForAmountString())
+ .property("contact_data", codecOptional(codecForChallengeContactData()))
+ .property("cashout_payto_uri", codecOptional(codecForPaytoString()))
+ .build("TalerCorebankApi.AccountData");
export const codecForChallengeContactData =
(): Codec<TalerCorebankApi.ChallengeContactData> =>
buildCodecForObject<TalerCorebankApi.ChallengeContactData>()
.property("email", codecOptional(codecForString()))
.property("phone", codecOptional(codecForString()))
- .build("TalerCorebankApi.ChallengeContactData")
+ .build("TalerCorebankApi.ChallengeContactData");
export const codecForBankAccountTransactionsResponse =
(): Codec<TalerCorebankApi.BankAccountTransactionsResponse> =>
buildCodecForObject<TalerCorebankApi.BankAccountTransactionsResponse>()
- .property("transactions", codecForList(codecForBankAccountTransactionInfo()))
+ .property(
+ "transactions",
+ codecForList(codecForBankAccountTransactionInfo()),
+ )
.build("TalerCorebankApi.BankAccountTransactionsResponse");
export const codecForBankAccountTransactionInfo =
@@ -357,7 +368,13 @@ export const codecForBankAccountTransactionInfo =
.property("creditor_payto_uri", codecForPaytoString())
.property("debtor_payto_uri", codecForPaytoString())
.property("amount", codecForAmountString())
- .property("direction", codecForEither(codecForConstString("debit"), codecForConstString("credit")))
+ .property(
+ "direction",
+ codecForEither(
+ codecForConstString("debit"),
+ codecForConstString("credit"),
+ ),
+ )
.property("subject", codecForString())
.property("row_id", codecForNumber())
.property("date", codecForTimestamp)
@@ -376,9 +393,12 @@ export const codecForBankAccountGetWithdrawalResponse =
.property("amount", codecForAmountString())
.property("aborted", codecForBoolean())
.property("confirmation_done", codecForBoolean())
- .property("selected_exchange_account", codecOptional(codecForPaytoString()))
+ .property(
+ "selected_exchange_account",
+ codecOptional(codecForPaytoString()),
+ )
.property("selected_reserve_pub", codecOptional(codecForString()))
- .property("selection_done", (codecForBoolean()))
+ .property("selection_done", codecForBoolean())
.build("TalerCorebankApi.BankAccountGetWithdrawalResponse");
export const codecForCashoutPending =
@@ -401,18 +421,23 @@ export const codecForCashinConversionResponse =
.property("amount_debit", codecForAmountString())
.build("TalerCorebankApi.CashinConversionResponse");
-export const codecForCashouts =
- (): Codec<TalerCorebankApi.Cashouts> =>
- buildCodecForObject<TalerCorebankApi.Cashouts>()
- .property("cashouts", codecForList(codecForCashoutInfo()))
- .build("TalerCorebankApi.Cashouts");
-
-export const codecForCashoutInfo =
- (): Codec<TalerCorebankApi.CashoutInfo> =>
- buildCodecForObject<TalerCorebankApi.CashoutInfo>()
- .property("cashout_id", codecForString())
- .property("status", codecForEither(codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed"),))
- .build("TalerCorebankApi.CashoutInfo");
+export const codecForCashouts = (): Codec<TalerCorebankApi.Cashouts> =>
+ buildCodecForObject<TalerCorebankApi.Cashouts>()
+ .property("cashouts", codecForList(codecForCashoutInfo()))
+ .build("TalerCorebankApi.Cashouts");
+
+export const codecForCashoutInfo = (): Codec<TalerCorebankApi.CashoutInfo> =>
+ buildCodecForObject<TalerCorebankApi.CashoutInfo>()
+ .property("cashout_id", codecForString())
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("pending"),
+ codecForConstString("aborted"),
+ codecForConstString("confirmed"),
+ ),
+ )
+ .build("TalerCorebankApi.CashoutInfo");
export const codecForGlobalCashouts =
(): Codec<TalerCorebankApi.GlobalCashouts> =>
@@ -425,7 +450,14 @@ export const codecForGlobalCashoutInfo =
buildCodecForObject<TalerCorebankApi.GlobalCashoutInfo>()
.property("cashout_id", codecForString())
.property("username", codecForString())
- .property("status", codecForEither(codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed"),))
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("pending"),
+ codecForConstString("aborted"),
+ codecForConstString("confirmed"),
+ ),
+ )
.build("TalerCorebankApi.GlobalCashoutInfo");
export const codecForCashoutStatusResponse =
@@ -436,7 +468,14 @@ export const codecForCashoutStatusResponse =
.property("confirmation_time", codecForTimestamp)
.property("creation_time", codecForTimestamp)
// .property("credit_payto_uri", codecForPaytoString())
- .property("status", codecForEither(codecForConstString("pending"), codecForConstString("aborted"), codecForConstString("confirmed")))
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("pending"),
+ codecForConstString("aborted"),
+ codecForConstString("confirmed"),
+ ),
+ )
.property("subject", codecForString())
.build("TalerCorebankApi.CashoutStatusResponse");
@@ -449,12 +488,13 @@ export const codecForConversionRatesResponse =
.property("sell_out_fee", codecForDecimalNumber())
.build("TalerCorebankApi.ConversionRatesResponse");
-
-export const codecForMonitorResponse = (): Codec<TalerCorebankApi.MonitorResponse> => buildCodecForUnion<TalerCorebankApi.MonitorResponse>()
- .discriminateOn("type")
- .alternative("no-conversions", codecForMonitorNoConversion())
- .alternative("with-conversions", codecForMonitorWithCashout())
- .build("TalerWireGatewayApi.IncomingBankTransaction");
+export const codecForMonitorResponse =
+ (): Codec<TalerCorebankApi.MonitorResponse> =>
+ buildCodecForUnion<TalerCorebankApi.MonitorResponse>()
+ .discriminateOn("type")
+ .alternative("no-conversions", codecForMonitorNoConversion())
+ .alternative("with-conversions", codecForMonitorWithCashout())
+ .build("TalerWireGatewayApi.IncomingBankTransaction");
export const codecForMonitorNoConversion =
(): Codec<TalerCorebankApi.MonitorNoConversion> =>
@@ -515,7 +555,10 @@ export const codecForMerchantIncomingHistory =
(): Codec<TalerRevenueApi.MerchantIncomingHistory> =>
buildCodecForObject<TalerRevenueApi.MerchantIncomingHistory>()
.property("credit_account", codecForPaytoString())
- .property("incoming_transactions", codecForList(codecForMerchantIncomingBankTransaction()))
+ .property(
+ "incoming_transactions",
+ codecForList(codecForMerchantIncomingBankTransaction()),
+ )
.build("TalerRevenueApi.MerchantIncomingHistory");
export const codecForMerchantIncomingBankTransaction =
@@ -540,14 +583,19 @@ export const codecForIncomingHistory =
(): Codec<TalerWireGatewayApi.IncomingHistory> =>
buildCodecForObject<TalerWireGatewayApi.IncomingHistory>()
.property("credit_account", codecForPaytoString())
- .property("incoming_transactions", codecForList(codecForIncomingBankTransaction()))
+ .property(
+ "incoming_transactions",
+ codecForList(codecForIncomingBankTransaction()),
+ )
.build("TalerWireGatewayApi.IncomingHistory");
-export const codecForIncomingBankTransaction = (): Codec<TalerWireGatewayApi.IncomingBankTransaction> => buildCodecForUnion<TalerWireGatewayApi.IncomingBankTransaction>()
- .discriminateOn("type")
- .alternative("RESERVE", codecForIncomingReserveTransaction())
- .alternative("WAD", codecForIncomingWadTransaction())
- .build("TalerWireGatewayApi.IncomingBankTransaction");
+export const codecForIncomingBankTransaction =
+ (): Codec<TalerWireGatewayApi.IncomingBankTransaction> =>
+ buildCodecForUnion<TalerWireGatewayApi.IncomingBankTransaction>()
+ .discriminateOn("type")
+ .alternative("RESERVE", codecForIncomingReserveTransaction())
+ .alternative("WAD", codecForIncomingWadTransaction())
+ .build("TalerWireGatewayApi.IncomingBankTransaction");
export const codecForIncomingReserveTransaction =
(): Codec<TalerWireGatewayApi.IncomingReserveTransaction> =>
@@ -577,7 +625,10 @@ export const codecForOutgoingHistory =
(): Codec<TalerWireGatewayApi.OutgoingHistory> =>
buildCodecForObject<TalerWireGatewayApi.OutgoingHistory>()
.property("debit_account", codecForPaytoString())
- .property("outgoing_transactions", codecForList(codecForOutgoingBankTransaction()))
+ .property(
+ "outgoing_transactions",
+ codecForList(codecForOutgoingBankTransaction()),
+ )
.build("TalerWireGatewayApi.OutgoingHistory");
export const codecForOutgoingBankTransaction =
@@ -598,20 +649,18 @@ export const codecForAddIncomingResponse =
.property("timestamp", codecForTimestamp)
.build("TalerWireGatewayApi.AddIncomingResponse");
-export const codecForAmlRecords =
- (): Codec<TalerExchangeApi.AmlRecords> =>
- buildCodecForObject<TalerExchangeApi.AmlRecords>()
- .property("records", codecForList(codecForAmlRecord()))
- .build("TalerExchangeApi.PublicAccountsResponse");
-
-export const codecForAmlRecord =
- (): Codec<TalerExchangeApi.AmlRecord> =>
- buildCodecForObject<TalerExchangeApi.AmlRecord>()
- .property("current_state", codecForNumber())
- .property("h_payto", codecForString())
- .property("rowid", codecForNumber())
- .property("threshold", codecForAmountString())
- .build("TalerExchangeApi.AmlRecord");
+export const codecForAmlRecords = (): Codec<TalerExchangeApi.AmlRecords> =>
+ buildCodecForObject<TalerExchangeApi.AmlRecords>()
+ .property("records", codecForList(codecForAmlRecord()))
+ .build("TalerExchangeApi.PublicAccountsResponse");
+
+export const codecForAmlRecord = (): Codec<TalerExchangeApi.AmlRecord> =>
+ buildCodecForObject<TalerExchangeApi.AmlRecord>()
+ .property("current_state", codecForNumber())
+ .property("h_payto", codecForString())
+ .property("rowid", codecForNumber())
+ .property("threshold", codecForAmountString())
+ .build("TalerExchangeApi.AmlRecord");
export const codecForAmlDecisionDetails =
(): Codec<TalerExchangeApi.AmlDecisionDetails> =>
@@ -636,27 +685,24 @@ interface KycDetail {
collection_time: Timestamp;
expiration_time: Timestamp;
}
-export const codecForKycDetail =
- (): Codec<TalerExchangeApi.KycDetail> =>
- buildCodecForObject<TalerExchangeApi.KycDetail>()
- .property("provider_section", codecForString())
- .property("attributes", codecOptional(codecForAny()))
- .property("collection_time", codecForTimestamp)
- .property("expiration_time", codecForTimestamp)
- .build("TalerExchangeApi.KycDetail");
-
-export const codecForAmlDecision =
- (): Codec<TalerExchangeApi.AmlDecision> =>
- buildCodecForObject<TalerExchangeApi.AmlDecision>()
- .property("justification", codecForString())
- .property("new_threshold", codecForAmountString())
- .property("h_payto", codecForString())
- .property("new_state", codecForNumber())
- .property("officer_sig", codecForString())
- .property("decision_time", codecForTimestamp)
- .property("kyc_requirements", codecOptional(codecForList(codecForString())))
- .build("TalerExchangeApi.AmlDecision");
-
+export const codecForKycDetail = (): Codec<TalerExchangeApi.KycDetail> =>
+ buildCodecForObject<TalerExchangeApi.KycDetail>()
+ .property("provider_section", codecForString())
+ .property("attributes", codecOptional(codecForAny()))
+ .property("collection_time", codecForTimestamp)
+ .property("expiration_time", codecForTimestamp)
+ .build("TalerExchangeApi.KycDetail");
+
+export const codecForAmlDecision = (): Codec<TalerExchangeApi.AmlDecision> =>
+ buildCodecForObject<TalerExchangeApi.AmlDecision>()
+ .property("justification", codecForString())
+ .property("new_threshold", codecForAmountString())
+ .property("h_payto", codecForString())
+ .property("new_state", codecForNumber())
+ .property("officer_sig", codecForString())
+ .property("decision_time", codecForTimestamp)
+ .property("kyc_requirements", codecOptional(codecForList(codecForString())))
+ .build("TalerExchangeApi.AmlDecision");
// version: string;
@@ -710,23 +756,29 @@ export const codecForConversionInfo =
.property("cashin_min_amount", codecForAmountString())
.property("cashin_ratio", codecForString())
// .property("cashin_ratio", codecForDecimalNumber())
- .property("cashin_rounding_mode", codecForEither(
- codecForConstString("zero"),
- codecForConstString("up"),
- codecForConstString("nearest")
- ))
+ .property(
+ "cashin_rounding_mode",
+ codecForEither(
+ codecForConstString("zero"),
+ codecForConstString("up"),
+ codecForConstString("nearest"),
+ ),
+ )
.property("cashin_tiny_amount", codecForAmountString())
.property("cashout_fee", codecForAmountString())
.property("cashout_min_amount", codecForAmountString())
.property("cashout_ratio", codecForString())
// .property("cashout_ratio", codecForDecimalNumber())
- .property("cashout_rounding_mode", codecForEither(
- codecForConstString("zero"),
- codecForConstString("up"),
- codecForConstString("nearest")
- ))
+ .property(
+ "cashout_rounding_mode",
+ codecForEither(
+ codecForConstString("zero"),
+ codecForConstString("up"),
+ codecForConstString("nearest"),
+ ),
+ )
.property("cashout_tiny_amount", codecForAmountString())
- .build("ConversionBankConfig.ConversionInfo")
+ .build("ConversionBankConfig.ConversionInfo");
export const codecForConversionBankConfig =
(): Codec<TalerBankConversionApi.IntegrationConfig> =>
@@ -734,7 +786,10 @@ export const codecForConversionBankConfig =
.property("name", codecForConstString("taler-conversion-info"))
.property("version", codecForString())
.property("regional_currency", codecForString())
- .property("regional_currency_specification", codecForCurrencySpecificiation())
+ .property(
+ "regional_currency_specification",
+ codecForCurrencySpecificiation(),
+ )
.property("fiat_currency", codecForString())
.property("fiat_currency_specification", codecForCurrencySpecificiation())
// .property("conversion_info", codecOptional(codecForConversionInfo()))
@@ -742,30 +797,35 @@ export const codecForConversionBankConfig =
.property("cashin_fee", codecForAmountString())
.property("cashin_min_amount", codecForAmountString())
.property("cashin_ratio", codecForString())
- .property("cashin_rounding_mode", codecForEither(
- codecForConstString("zero"),
- codecForConstString("up"),
- codecForConstString("nearest")
- ))
+ .property(
+ "cashin_rounding_mode",
+ codecForEither(
+ codecForConstString("zero"),
+ codecForConstString("up"),
+ codecForConstString("nearest"),
+ ),
+ )
.property("cashin_tiny_amount", codecForAmountString())
.property("cashout_fee", codecForAmountString())
.property("cashout_min_amount", codecForAmountString())
.property("cashout_ratio", codecForString())
- .property("cashout_rounding_mode", codecForEither(
- codecForConstString("zero"),
- codecForConstString("up"),
- codecForConstString("nearest")
- ))
+ .property(
+ "cashout_rounding_mode",
+ codecForEither(
+ codecForConstString("zero"),
+ codecForConstString("up"),
+ codecForConstString("nearest"),
+ ),
+ )
.property("cashout_tiny_amount", codecForAmountString())
//////////////////////////
- .build("ConversionBankConfig.IntegrationConfig")
+ .build("ConversionBankConfig.IntegrationConfig");
// export const codecFor =
// (): Codec<TalerWireGatewayApi.PublicAccountsResponse> =>
// buildCodecForObject<TalerWireGatewayApi.PublicAccountsResponse>()
// .property("", codecForString())
// .build("TalerWireGatewayApi.PublicAccountsResponse");
-
type EmailAddress = string;
type PhoneNumber = string;
type EddsaSignature = string;
@@ -782,7 +842,7 @@ type CoinEnvelope = RSACoinEnvelope | CSCoinEnvelope;
// coin's public EdDSA key.
interface RSACoinEnvelope {
cipher: "RSA" | "RSA+age_restricted";
- rsa_blinded_planchet: string; // Crockford Base32 encoded
+ rsa_blinded_planchet: string; // Crockford Base32 encoded
}
// For denomination signatures based on Blind Clause-Schnorr, the planchet
// consists of the public nonce and two Curve25519 scalars which are two
@@ -790,7 +850,7 @@ interface RSACoinEnvelope {
// See https://taler.net/papers/cs-thesis.pdf for details.
interface CSCoinEnvelope {
cipher: "CS" | "CS+age_restricted";
- cs_nonce: string; // Crockford Base32 encoded
+ cs_nonce: string; // Crockford Base32 encoded
cs_blinded_c0: string; // Crockford Base32 encoded
cs_blinded_c1: string; // Crockford Base32 encoded
}
@@ -799,11 +859,11 @@ interface CSCoinEnvelope {
// a 256-bit nonce, converted to Crockford Base32.
type DenominationBlindingKeyP = string;
-const codecForURL = codecForString
-const codecForLibtoolVersion = codecForString
-const codecForCurrencyName = codecForString
-const codecForEddsaSignature = codecForString
-const codecForDecimalNumber = codecForNumber
+const codecForURL = codecForString;
+const codecForLibtoolVersion = codecForString;
+const codecForCurrencyName = codecForString;
+const codecForEddsaSignature = codecForString;
+const codecForDecimalNumber = codecForNumber;
enum TanChannel {
SMS = "sms",
@@ -811,9 +871,7 @@ enum TanChannel {
}
export namespace TalerWireGatewayApi {
-
export interface TransferResponse {
-
// Timestamp that indicates when the wire transfer will be executed.
// In cases where the wire transfer gateway is unable to know when
// the wire transfer will be executed, the time at which the request
@@ -850,7 +908,6 @@ export namespace TalerWireGatewayApi {
}
export interface IncomingHistory {
-
// Array of incoming transactions.
incoming_transactions: IncomingBankTransaction[];
@@ -859,7 +916,6 @@ export namespace TalerWireGatewayApi {
// Credit account is shared by all incoming transactions
// as per the nature of the request.
credit_account: PaytoString;
-
}
// Union discriminated by the "type" field.
@@ -884,7 +940,6 @@ export namespace TalerWireGatewayApi {
// The reserve public key extracted from the transaction details.
reserve_pub: EddsaPublicKey;
-
}
export interface IncomingWadTransaction {
@@ -913,9 +968,7 @@ export namespace TalerWireGatewayApi {
wad_id: WadId;
}
-
export interface OutgoingHistory {
-
// Array of outgoing transactions.
outgoing_transactions: OutgoingBankTransaction[];
@@ -924,11 +977,9 @@ export namespace TalerWireGatewayApi {
// Credit account is shared by all incoming transactions
// as per the nature of the request.
debit_account: PaytoString;
-
}
export interface OutgoingBankTransaction {
-
// Opaque identifier of the returned record.
row_id: SafeUint64;
@@ -964,7 +1015,6 @@ export namespace TalerWireGatewayApi {
}
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
// the wire transfer will be executed, the time at which the request
@@ -977,14 +1027,10 @@ export namespace TalerWireGatewayApi {
// Opaque ID of the transaction that the bank has made.
row_id: SafeUint64;
}
-
-
-
}
export namespace TalerRevenueApi {
export interface MerchantIncomingHistory {
-
// Array of incoming transactions.
incoming_transactions: MerchantIncomingBankTransaction[];
@@ -993,11 +1039,9 @@ export namespace TalerRevenueApi {
// Credit account is shared by all incoming transactions
// as per the nature of the request.
credit_account: PaytoString;
-
}
export interface MerchantIncomingBankTransaction {
-
// Opaque identifier of the returned record.
row_id: SafeUint64;
@@ -1019,7 +1063,6 @@ export namespace TalerRevenueApi {
}
export namespace TalerBankConversionApi {
-
export interface ConversionInfo {
// Exchange rate to buy regional currency from fiat
// cashin_ratio: DecimalNumber;
@@ -1097,7 +1140,6 @@ export namespace TalerBankConversionApi {
// bank account, according to 'amount_debit'.
amount_credit: AmountString;
}
-
}
export namespace TalerBankIntegrationApi {
export interface BankVersion {
@@ -1110,7 +1152,7 @@ export namespace TalerBankIntegrationApi {
currency: string;
// How the bank SPA should render this currency.
- currency_specification: CurrencySpecification;
+ currency_specification?: CurrencySpecification;
// Name of the API.
name: "taler-bank-integration";
@@ -1150,7 +1192,6 @@ export namespace TalerBankIntegrationApi {
}
export interface BankWithdrawalOperationPostRequest {
-
// Reserve public key.
reserve_pub: string;
@@ -1159,7 +1200,6 @@ export namespace TalerBankIntegrationApi {
}
export interface BankWithdrawalOperationPostResponse {
-
// The transfer has been confirmed and registered by the bank.
// Does not guarantee that the funds have arrived at the exchange already.
transfer_done: boolean;
@@ -1171,23 +1211,18 @@ export namespace TalerBankIntegrationApi {
// It may contain withdrawal operation id
confirm_transfer_url?: string;
}
-
-
}
export namespace TalerCorebankApi {
-
export interface IntegrationConfig {
// libtool-style representation of the Bank protocol version, see
// https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
// The format is "current:revision:age".
version: string;
- // How the bank SPA should render this currency.
- currency: CurrencySpecification;
+ currency: String;
// Name of the API.
name: "taler-bank-integration";
-
}
export interface Config {
// Name of this API, always "taler-corebank".
@@ -1323,7 +1358,6 @@ export namespace TalerCorebankApi {
internal_payto_uri?: PaytoString;
}
export interface ChallengeContactData {
-
// E-Mail address
email?: EmailAddress;
@@ -1332,7 +1366,6 @@ export namespace TalerCorebankApi {
}
export interface AccountReconfiguration {
-
// Addresses where to send the TAN for transactions.
// Currently only used for cashouts.
// If missing, cashouts will fail.
@@ -1357,11 +1390,9 @@ export namespace TalerCorebankApi {
// If present, change the max debit allowed for this user
// Only admin can change this property.
- debit_threshold?: AmountString
-
+ debit_threshold?: AmountString;
}
-
export interface AccountPasswordChange {
// New password.
new_password: string;
@@ -1428,9 +1459,7 @@ export namespace TalerCorebankApi {
cashout_payto_uri?: PaytoString;
}
-
export interface CashoutRequest {
-
// Nonce to make the request idempotent. Requests with the same
// request_uid that differ in any of the other fields
// are rejected.
@@ -1521,7 +1550,6 @@ export namespace TalerCorebankApi {
}
export interface ConversionRatesResponse {
-
// Exchange rate to buy the local currency from the external one
buy_at_ratio: DecimalNumber;
@@ -1536,12 +1564,14 @@ export namespace TalerCorebankApi {
}
export enum MonitorTimeframeParam {
- hour, day, month, year, decade,
+ hour,
+ day,
+ month,
+ year,
+ decade,
}
- export type MonitorResponse =
- | MonitorNoConversion
- | MonitorWithConversion;
+ export type MonitorResponse = MonitorNoConversion | MonitorWithConversion;
// Monitoring stats when conversion is not supported
export interface MonitorNoConversion {
@@ -1607,12 +1637,9 @@ export namespace TalerCorebankApi {
// exchange to another bank account.
talerOutVolume: AmountString;
}
-
-
}
export namespace TalerExchangeApi {
-
export enum AmlState {
normal = 0,
pending = 1,
@@ -1620,12 +1647,10 @@ export namespace TalerExchangeApi {
}
export interface AmlRecords {
-
// Array of AML records matching the query.
records: AmlRecord[];
}
export interface AmlRecord {
-
// Which payto-address is this record about.
// Identifies a GNU Taler wallet or an affected bank account.
h_payto: PaytoHash;
@@ -1638,11 +1663,9 @@ export namespace TalerExchangeApi {
// RowID of the record.
rowid: Integer;
-
}
export interface AmlDecisionDetails {
-
// Array of AML decisions made for this account. Possibly
// contains only the most recent decision if "history" was
// not set to 'true'.
@@ -1652,7 +1675,6 @@ export namespace TalerExchangeApi {
kyc_attributes: KycDetail[];
}
export interface AmlDecisionDetail {
-
// What was the justification given?
justification: string;
@@ -1667,10 +1689,8 @@ export namespace TalerExchangeApi {
// Who made the decision?
decider_pub: AmlOfficerPublicKeyP;
-
}
export interface KycDetail {
-
// Name of the configuration section that specifies the provider
// which was used to collect the KYC details
provider_section: string;
@@ -1685,12 +1705,9 @@ export namespace TalerExchangeApi {
// Time when the validity of the KYC data will expire
expiration_time: Timestamp;
-
}
-
export interface AmlDecision {
-
// Human-readable justification for the decision.
justification: string;
@@ -1719,7 +1736,6 @@ export namespace TalerExchangeApi {
kyc_requirements?: string[];
}
-
export interface ExchangeVersionResponse {
// libtool-style representation of the Exchange protocol version, see
// https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
@@ -1737,23 +1753,20 @@ export namespace TalerExchangeApi {
// Names of supported KYC requirements.
supported_kyc_requirements: string[];
-
}
export type AccountRestriction =
| RegexAccountRestriction
- | DenyAllAccountRestriction
+ | DenyAllAccountRestriction;
// Account restriction that disables this type of
// account for the indicated operation categorically.
export interface DenyAllAccountRestriction {
-
type: "deny";
}
// Accounts interacting with this type of account
// restriction must have a payto://-URI matching
// the given regex.
export interface RegexAccountRestriction {
-
type: "regex";
// Regular expression that the payto://-URI of the
@@ -1773,7 +1786,6 @@ export namespace TalerExchangeApi {
// Map from IETF BCP 47 language tags to localized
// human hints.
human_hint_i18n?: { [lang_tag: string]: string };
-
}
export interface WireAccount {
@@ -1800,7 +1812,6 @@ export namespace TalerExchangeApi {
// with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS.
master_sig: EddsaSignature;
}
-
}
export namespace TalerMerchantApi {
@@ -1827,7 +1838,6 @@ export namespace TalerMerchantApi {
// All currencies in this map are supported by
// the backend.
currencies: { [currency: string]: CurrencySpecification };
-
}
export interface ClaimRequest {
@@ -1856,7 +1866,6 @@ export namespace TalerMerchantApi {
// Text to be shown to the point-of-sale staff as a proof of
// payment.
pos_confirmation?: string;
-
}
interface PayRequest {
@@ -1869,7 +1878,6 @@ export namespace TalerMerchantApi {
// The session for which the payment is made (or replayed).
// Only set for session-based payments.
session_id?: string;
-
}
export interface CoinPaySig {
// Signature by the coin.
@@ -1891,7 +1899,6 @@ export namespace TalerMerchantApi {
exchange_url: string;
}
-
interface StatusPaid {
// Was the payment refunded (even partially, via refund or abort)?
refunded: boolean;
@@ -1926,7 +1933,6 @@ export namespace TalerMerchantApi {
}
interface PaidRefundStatusResponse {
-
// Text to be shown to the point-of-sale staff as a proof of
// payment (present only if re-usable OTP algorithm is used).
pos_confirmation?: string;
@@ -1953,7 +1959,6 @@ export namespace TalerMerchantApi {
}
interface AbortRequest {
-
// Hash of the order's contract terms (this is used to authenticate the
// wallet/customer in case $ORDER_ID is guessable).
h_contract: HashCode;
@@ -1974,7 +1979,6 @@ export namespace TalerMerchantApi {
exchange_url: string;
}
interface AbortResponse {
-
// List of refund responses about the coins that the wallet
// requested an abort for. In the same order as the coins
// from the original request.
@@ -2034,7 +2038,6 @@ export namespace TalerMerchantApi {
// Public key of the merchant.
merchant_pub: EddsaPublicKey;
-
}
type MerchantCoinRefundStatus =
| MerchantCoinRefundSuccessStatus
@@ -2104,7 +2107,6 @@ export namespace TalerMerchantApi {
}
interface RewardInformation {
-
// Exchange from which the reward will be withdrawn. Needed by the
// wallet to determine denominations, fees, etc.
exchange_url: string;
@@ -2121,7 +2123,6 @@ export namespace TalerMerchantApi {
}
interface RewardPickupRequest {
-
// List of planchets the wallet wants to use for the reward.
planchets: PlanchetDetail[];
}
@@ -2134,19 +2135,16 @@ export namespace TalerMerchantApi {
coin_ev: CoinEnvelope;
}
interface RewardResponse {
-
// Blind RSA signatures over the planchets.
// The order of the signatures matches the planchets list.
blind_sigs: BlindSignature[];
}
interface BlindSignature {
-
// The (blind) RSA signature. Still needs to be unblinded.
blind_sig: BlindedRsaSignature;
}
interface InstanceConfigurationMessage {
-
// Name of the merchant instance to create (will become $INSTANCE).
// Must match the regex ^[A-Za-z0-9][A-Za-z0-9_.@-]+$.
id: string;
@@ -2192,7 +2190,6 @@ export namespace TalerMerchantApi {
// If the frontend does NOT specify a payment deadline, how long should
// offers we make be valid by default?
default_pay_delay: RelativeTime;
-
}
interface InstanceAuthConfigurationMessage {
@@ -2210,7 +2207,6 @@ export namespace TalerMerchantApi {
// the value must be provided in a "Authorization: Bearer $token"
// header.
token?: string;
-
}
interface LoginTokenRequest {
@@ -2244,7 +2240,6 @@ export namespace TalerMerchantApi {
}
interface InstanceReconfigurationMessage {
-
// Merchant name corresponding to this instance.
name: string;
@@ -2283,7 +2278,6 @@ export namespace TalerMerchantApi {
// If the frontend does NOT specify a payment deadline, how long should
// offers we make be valid by default?
default_pay_delay: RelativeTime;
-
}
interface InstancesResponse {
@@ -2320,7 +2314,6 @@ export namespace TalerMerchantApi {
}
interface QueryInstancesResponse {
-
// Merchant name corresponding to this instance.
name: string;
@@ -2366,11 +2359,9 @@ export namespace TalerMerchantApi {
auth: {
type: "external" | "token";
};
-
}
interface AccountKycRedirects {
-
// Array of pending KYCs.
pending_kycs: MerchantAccountKycRedirect[];
@@ -2379,7 +2370,6 @@ export namespace TalerMerchantApi {
}
interface MerchantAccountKycRedirect {
-
// URL that the user should open in a browser to
// proceed with the KYC process (as returned
// by the exchange's /kyc-check/ endpoint).
@@ -2395,11 +2385,9 @@ export namespace TalerMerchantApi {
// Our bank wire account this is about.
payto_uri: PaytoString;
-
}
interface ExchangeKycTimeout {
-
// Base URL of the exchange this is about.
exchange_url: string;
@@ -2411,11 +2399,9 @@ export namespace TalerMerchantApi {
// information about the KYC status.
// 0 if there was no response at all.
exchange_http_status: number;
-
}
interface AccountAddDetails {
-
// payto:// URI of the account.
payto_uri: PaytoString;
@@ -2429,15 +2415,12 @@ export namespace TalerMerchantApi {
// or PATCH requests to update (or delete) credentials.
// To really delete credentials, set them to the type: "none".
credit_facade_credentials?: FacadeCredentials;
-
}
- type FacadeCredentials =
- | NoFacadeCredentials
- | BasicAuthFacadeCredentials;
+ type FacadeCredentials = NoFacadeCredentials | BasicAuthFacadeCredentials;
interface NoFacadeCredentials {
type: "none";
- };
+ }
interface BasicAuthFacadeCredentials {
type: "basic";
@@ -2446,19 +2429,16 @@ export namespace TalerMerchantApi {
// Password to use to authenticate
password: string;
- };
+ }
interface AccountAddResponse {
-
// Hash over the wire details (including over the salt).
h_wire: HashCode;
// Salt used to compute h_wire.
salt: HashCode;
-
}
interface AccountPatchDetails {
-
// URL from where the merchant can download information
// about incoming wire transfers to this account.
credit_facade_url?: string;
@@ -2474,12 +2454,10 @@ export namespace TalerMerchantApi {
}
interface AccountsSummaryResponse {
-
// List of accounts that are known for the instance.
accounts: BankAccountEntry[];
}
interface BankAccountEntry {
-
// payto:// URI of the account.
payto_uri: PaytoString;
@@ -2499,7 +2477,6 @@ export namespace TalerMerchantApi {
}
interface ProductAddDetail {
-
// Product ID to use.
product_id: string;
@@ -2539,11 +2516,9 @@ export namespace TalerMerchantApi {
// Minimum age buyer must have (in years). Default is 0.
minimum_age?: Integer;
-
}
interface ProductPatchDetail {
-
// Human-readable product description.
description: string;
@@ -2583,7 +2558,6 @@ export namespace TalerMerchantApi {
// Minimum age buyer must have (in years). Default is 0.
minimum_age?: Integer;
-
}
interface InventorySummaryResponse {
@@ -2591,15 +2565,12 @@ export namespace TalerMerchantApi {
products: InventoryEntry[];
}
-
interface InventoryEntry {
// Product identifier, as found in the product.
product_id: string;
-
}
interface ProductDetail {
-
// Human-readable product description.
description: string;
@@ -2642,10 +2613,8 @@ export namespace TalerMerchantApi {
// Minimum age buyer must have (in years).
minimum_age?: Integer;
-
}
interface LockRequest {
-
// UUID that identifies the frontend performing the lock
// Must be unique for the lifetime of the lock.
lock_uuid: string;
@@ -2655,7 +2624,6 @@ export namespace TalerMerchantApi {
// How many units should be locked?
quantity: Integer;
-
}
interface PostOrderRequest {
@@ -2735,7 +2703,6 @@ export namespace TalerMerchantApi {
token?: ClaimToken;
}
interface OutOfStockResponse {
-
// Product ID of an out-of-stock item.
product_id: string;
@@ -2756,7 +2723,6 @@ export namespace TalerMerchantApi {
orders: OrderHistoryEntry[];
}
interface OrderHistoryEntry {
-
// Order ID of the transaction related to this entry.
order_id: string;
@@ -2782,9 +2748,10 @@ export namespace TalerMerchantApi {
paid: boolean;
}
- type MerchantOrderStatusResponse = CheckPaymentPaidResponse |
- CheckPaymentClaimedResponse |
- CheckPaymentUnpaidResponse;
+ type MerchantOrderStatusResponse =
+ | CheckPaymentPaidResponse
+ | CheckPaymentClaimedResponse
+ | CheckPaymentUnpaidResponse;
interface CheckPaymentPaidResponse {
// The customer paid for this contract.
order_status: "paid";
@@ -2842,7 +2809,6 @@ export namespace TalerMerchantApi {
// Contract terms.
contract_terms: ContractTerms;
-
}
interface CheckPaymentUnpaidResponse {
// The order was neither claimed nor paid.
@@ -2924,7 +2890,6 @@ export namespace TalerMerchantApi {
}
interface ForgetRequest {
-
// Array of valid JSON paths to forgettable fields in the order's
// contract terms.
fields: string[];
@@ -2938,7 +2903,6 @@ export namespace TalerMerchantApi {
reason: string;
}
interface MerchantRefundResponse {
-
// URL (handled by the backend) that the wallet should access to
// trigger refund processing.
// taler://refund/...
@@ -3085,7 +3049,6 @@ export namespace TalerMerchantApi {
exchange_url: string;
}
interface RewardStatusEntry {
-
// Unique identifier for the reward.
reward_id: HashCode;
@@ -3154,12 +3117,10 @@ export namespace TalerMerchantApi {
}
interface RewardsResponse {
-
// List of rewards that are present in the backend.
rewards: Reward[];
}
interface Reward {
-
// ID of the reward in the backend database.
row_id: number;
@@ -3171,7 +3132,6 @@ export namespace TalerMerchantApi {
}
interface OtpDeviceAddDetails {
-
// Device ID to use.
otp_device_id: string;
@@ -3189,7 +3149,6 @@ export namespace TalerMerchantApi {
}
interface OtpDevicePatchDetails {
-
// Human-readable description for the device.
otp_device_description: string;
@@ -3204,12 +3163,10 @@ export namespace TalerMerchantApi {
}
interface OtpDeviceSummaryResponse {
-
// Array of devices that are present in our backend.
otp_devices: OtpDeviceEntry[];
}
interface OtpDeviceEntry {
-
// Device identifier.
otp_device_id: string;
@@ -3218,7 +3175,6 @@ export namespace TalerMerchantApi {
}
interface OtpDeviceDetails {
-
// Human-readable description for the device.
device_description: string;
@@ -3227,10 +3183,8 @@ export namespace TalerMerchantApi {
// Counter for counter-based OTP devices.
otp_ctr?: Integer;
-
}
interface TemplateAddDetails {
-
// Template ID to use.
template_id: string;
@@ -3245,7 +3199,6 @@ export namespace TalerMerchantApi {
template_contract: TemplateContractDetails;
}
interface TemplateContractDetails {
-
// Human-readable summary for the template.
summary?: string;
@@ -3266,10 +3219,8 @@ export namespace TalerMerchantApi {
// The time the customer need to pay before his order will be deleted.
// It is deleted if the customer did not pay and if the duration is over.
pay_duration: RelativeTime;
-
}
interface TemplatePatchDetails {
-
// Human-readable description for the template.
template_description: string;
@@ -3279,27 +3230,21 @@ export namespace TalerMerchantApi {
// Additional information in a separate template.
template_contract: TemplateContractDetails;
-
}
interface TemplateSummaryResponse {
-
// List of templates that are present in our backend.
templates_list: TemplateEntry[];
}
-
interface TemplateEntry {
-
// Template identifier, as found in the template.
template_id: string;
// Human-readable description for the template.
template_description: string;
-
}
interface TemplateDetails {
-
// Human-readable description for the template.
template_description: string;
@@ -3311,7 +3256,6 @@ export namespace TalerMerchantApi {
template_contract: TemplateContractDetails;
}
interface UsingTemplateDetails {
-
// Summary of the template
summary?: string;
@@ -3320,7 +3264,6 @@ export namespace TalerMerchantApi {
}
interface WebhookAddDetails {
-
// Webhook ID to use.
webhook_id: string;
@@ -3338,11 +3281,9 @@ export namespace TalerMerchantApi {
// Body template by the webhook
body_template?: string;
-
}
interface WebhookPatchDetails {
-
// The event of the webhook: why the webhook is used.
event_type: string;
@@ -3357,29 +3298,22 @@ export namespace TalerMerchantApi {
// Body template by the webhook
body_template?: string;
-
}
interface WebhookSummaryResponse {
-
// Return webhooks that are present in our backend.
webhooks: WebhookEntry[];
-
}
-
interface WebhookEntry {
-
// Webhook identifier, as found in the webhook.
webhook_id: string;
// The event of the webhook: why the webhook is used.
event_type: string;
-
}
interface WebhookDetails {
-
// The event of the webhook: why the webhook is used.
event_type: string;
@@ -3394,7 +3328,6 @@ export namespace TalerMerchantApi {
// Body template by the webhook
body_template?: string;
-
}
interface ContractTerms {
@@ -3639,5 +3572,4 @@ export namespace TalerMerchantApi {
// Master public key of the exchange.
master_pub: EddsaPublicKey;
}
-
-} \ No newline at end of file
+}
diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts
index f21efc516..e32c5a99d 100644
--- a/packages/taler-util/src/taler-types.ts
+++ b/packages/taler-util/src/taler-types.ts
@@ -41,6 +41,10 @@ import {
codecOptional,
} from "./codec.js";
import { strcmp } from "./helpers.js";
+import {
+ CurrencySpecification,
+ codecForCurrencySpecificiation,
+} from "./index.js";
import { AgeCommitmentProof, Edx25519PublicKeyEnc } from "./taler-crypto.js";
import {
codecForAbsoluteTime,
@@ -1756,7 +1760,6 @@ export interface MerchantAbortPayRefundSuccessStatus {
exchange_pub: string;
}
-
export interface FutureKeysResponse {
future_denoms: any[];
@@ -2375,3 +2378,39 @@ export const codecForExchangeWireAccount = (): Codec<ExchangeWireAccount> =>
.property("master_sig", codecForString())
.property("payto_uri", codecForString())
.build("WireAccount");
+
+export type Integer = number;
+
+export interface BankConversionInfoConfig {
+ // libtool-style representation of the Bank protocol version, see
+ // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ // The format is "current:revision:age".
+ version: string;
+
+ // Name of the API.
+ name: "taler-conversion-info";
+
+ regional_currency: string;
+
+ fiat_currency: string;
+
+ // Currency used by this bank.
+ regional_currency_specification: CurrencySpecification;
+
+ // External currency used during conversion.
+ fiat_currency_specification: CurrencySpecification;
+}
+
+export const codecForBankConversionInfoConfig =
+ (): Codec<BankConversionInfoConfig> =>
+ buildCodecForObject<BankConversionInfoConfig>()
+ .property("name", codecForConstString("taler-conversion-info"))
+ .property("version", codecForString())
+ .property("fiat_currency", codecForString())
+ .property("regional_currency", codecForString())
+ .property("fiat_currency_specification", codecForCurrencySpecificiation())
+ .property(
+ "regional_currency_specification",
+ codecForCurrencySpecificiation(),
+ )
+ .build("BankConversionInfoConfig");
diff --git a/packages/taler-util/src/transactions-types.ts b/packages/taler-util/src/transactions-types.ts
index 3a7f4d541..f2bf49b00 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -51,6 +51,7 @@ import {
TalerErrorDetail,
TransactionIdStr,
TransactionStateFilter,
+ WithdrawalAccountInfo,
} from "./wallet-types.js";
export interface TransactionsRequest {
@@ -237,9 +238,13 @@ interface WithdrawalDetailsForManualTransfer {
* Payto URIs that the exchange supports.
*
* Already contains the amount and message.
+ *
+ * @deprecated in favor of exchangeCreditAccounts
*/
exchangePaytoUris: string[];
+ exchangeCreditAccounts?: WithdrawalAccountInfo[];
+
// Public key of the reserve
reservePub: string;
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index 148117673..346528029 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -52,6 +52,7 @@ import { PaytoUri } from "./payto.js";
import { AgeCommitmentProof } from "./taler-crypto.js";
import { TalerErrorCode } from "./taler-error-codes.js";
import {
+ AccountRestriction,
AmountString,
AuditorDenomSig,
CoinEnvelope,
@@ -78,8 +79,6 @@ import {
} from "./time.js";
import {
OrderShortInfo,
- TransactionMajorState,
- TransactionMinorState,
TransactionState,
TransactionType,
} from "./transactions-types.js";
@@ -1387,6 +1386,8 @@ export interface AcceptManualWithdrawalResult {
*/
reservePub: string;
+ withdrawalAccountsList: WithdrawalAccountInfo[];
+
transactionId: TransactionIdStr;
}
@@ -1416,10 +1417,17 @@ export interface ManualWithdrawalDetails {
/**
* Ways to pay the exchange.
+ *
+ * @deprecated in favor of withdrawalAccountList
*/
paytoUris: string[];
/**
+ * Ways to pay the exchange, including
+ */
+ withdrawalAccountList: WithdrawalAccountInfo[];
+
+ /**
* If the exchange supports age-restricted coins it will return
* the array of ages.
*/
@@ -1438,6 +1446,11 @@ export interface DenomSelectionState {
}[];
}
+export interface WireAccountDetails {
+ paytoUri: string;
+ creditRestrictions?: AccountRestriction[];
+}
+
/**
* Information about what will happen doing a withdrawal.
*
@@ -1451,6 +1464,8 @@ export interface ExchangeWithdrawalDetails {
*/
exchangeWireAccounts: string[];
+ withdrawalAccountList: WithdrawalAccountInfo[];
+
/**
* Selected denominations for withdraw.
*/
@@ -2736,3 +2751,8 @@ export interface TestingWaitTransactionRequest {
transactionId: string;
txState: TransactionState;
}
+
+export interface WithdrawalAccountInfo {
+ paytoUri: string;
+ transferAmount: AmountString;
+}
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index 56392f090..36ca128ae 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -164,7 +164,7 @@ export interface TalerCryptoInterface {
req: ContractTermsValidationRequest,
): Promise<ValidationResult>;
- createEddsaKeypair(req: unknown): Promise<EddsaKeypair>;
+ createEddsaKeypair(req: {}): Promise<EddsaKeypair>;
eddsaGetPublic(req: EddsaGetPublicRequest): Promise<EddsaGetPublicResponse>;
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 3e8452bcd..0cafae2a1 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -52,10 +52,10 @@ import {
TalerPreciseTimestamp,
TalerProtocolDuration,
TalerProtocolTimestamp,
- //TalerProtocolTimestamp,
TransactionIdStr,
UnblindedSignature,
WireInfo,
+ WithdrawalAccountInfo,
codecForAny,
} from "@gnu-taler/taler-util";
import { DbRetryInfo, TaskIdentifiers } from "./operations/common.js";
@@ -1373,6 +1373,11 @@ export interface WgInfoBankIntegrated {
export interface WgInfoBankManual {
withdrawalType: WithdrawalRecordType.BankManual;
+
+ /**
+ * Info about withdrawal accounts, possibly including currency conversion.
+ */
+ exchangeCreditAccounts?: WithdrawalAccountInfo[];
}
export interface WgInfoBankPeerPull {
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 7ee6275b0..b294c163e 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -720,6 +720,7 @@ function buildTransactionForManualWithdraw(
type: WithdrawalType.ManualTransfer,
reservePub: withdrawalGroup.reservePub,
exchangePaytoUris,
+ exchangeCreditAccounts: withdrawalGroup.wgInfo.exchangeCreditAccounts,
reserveIsReady:
withdrawalGroup.status === WithdrawalGroupStatus.Done ||
withdrawalGroup.status === WithdrawalGroupStatus.PendingReady,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 275d0aaf0..a5a6bded8 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -24,6 +24,7 @@ import {
AgeRestriction,
AmountJson,
AmountLike,
+ AmountString,
Amounts,
BankWithdrawDetails,
CancellationToken,
@@ -42,6 +43,7 @@ import {
LibtoolVersion,
Logger,
NotificationType,
+ PaytoUri,
TalerError,
TalerErrorCode,
TalerErrorDetail,
@@ -54,21 +56,25 @@ import {
TransactionType,
URL,
UnblindedSignature,
+ WireAccountDetails,
WithdrawUriInfoResponse,
+ WithdrawalAccountInfo,
addPaytoQueryParams,
canonicalizeBaseUrl,
codecForBankWithdrawalOperationPostResponse,
+ codecForCashinConversionResponse,
codecForExchangeWithdrawBatchResponse,
codecForIntegrationBankConfig,
codecForReserveStatus,
codecForWalletKycUuid,
codecForWithdrawOperationStatusResponse,
+ createEddsaKeyPair,
encodeCrock,
getErrorDetailFromException,
getRandomBytes,
j2s,
makeErrorDetail,
- parseWithdrawUri
+ parseWithdrawUri,
} from "@gnu-taler/taler-util";
import {
HttpRequestLibrary,
@@ -95,9 +101,8 @@ import {
import {
ExchangeDetailsRecord,
ExchangeEntryDbRecordStatus,
- PendingTaskType,
isWithdrawableDenom,
- timestampPreciseToDb
+ timestampPreciseToDb,
} from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import {
@@ -110,6 +115,7 @@ import {
makeExchangeListItem,
runLongpollAsync,
} from "../operations/common.js";
+import { PendingTaskType } from "../pending-types.js";
import { assertUnreachable } from "../util/assertUnreachable.js";
import {
selectForcedWithdrawalDenominations,
@@ -1751,8 +1757,23 @@ export async function getExchangeWithdrawalInfo(
logger.trace("updating exchange");
const { exchange, exchangeDetails } =
await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl);
+
+ if (exchangeDetails.currency != instructedAmount.currency) {
+ // Specifiying the amount in the conversion input currency is not yet supported.
+ // We might add support for it later.
+ throw new Error(
+ `withdrawal only supported when specifying target currency ${exchangeDetails.currency}`,
+ );
+ }
+
+ const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, {
+ exchangeDetails,
+ instructedAmount,
+ });
+
logger.trace("updating withdrawal denoms");
await updateWithdrawalDenoms(ws, exchangeBaseUrl);
+
logger.trace("getting candidate denoms");
const denoms = await getCandidateWithdrawalDenoms(ws, exchangeBaseUrl);
logger.trace("selecting withdrawal denoms");
@@ -1773,8 +1794,15 @@ export async function getExchangeWithdrawalInfo(
}
const exchangeWireAccounts: string[] = [];
+
for (const account of exchangeDetails.wireInfo.accounts) {
- exchangeWireAccounts.push(account.payto_uri);
+ const details: WireAccountDetails = {
+ paytoUri: account.payto_uri,
+ };
+ if (account.credit_restrictions) {
+ details.creditRestrictions = account.credit_restrictions;
+ }
+ exchangeWireAccounts.push(details.paytoUri);
}
let hasDenomWithAgeRestriction = false;
@@ -1854,6 +1882,7 @@ export async function getExchangeWithdrawalInfo(
earliestDepositExpiration,
exchangePaytoUris: paytoUris,
exchangeWireAccounts,
+ withdrawalAccountList,
exchangeVersion: exchangeDetails.protocolVersionRange || "unknown",
numOfferedDenoms: possibleDenoms.length,
selectedDenoms,
@@ -1946,15 +1975,6 @@ export async function getWithdrawalDetailsForUri(
};
}
-export async function getFundingPaytoUrisTx(
- ws: InternalWalletState,
- withdrawalGroupId: string,
-): Promise<string[]> {
- return await ws.db
- .mktx((x) => [x.exchanges, x.exchangeDetails, x.withdrawalGroups])
- .runReadWrite((tx) => getFundingPaytoUris(tx, withdrawalGroupId));
-}
-
export function augmentPaytoUrisForWithdrawal(
plainPaytoUris: string[],
reservePub: string,
@@ -2361,10 +2381,6 @@ export async function internalPrepareCreateWithdrawalGroup(
const exchangeInfo = await updateExchangeFromUrl(ws, canonExchange);
const exchangeDetails = exchangeInfo.exchangeDetails;
- if (!exchangeDetails) {
- logger.trace(exchangeDetails);
- throw Error("exchange not updated");
- }
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId: withdrawalGroup.withdrawalGroupId,
@@ -2566,6 +2582,60 @@ export async function acceptWithdrawalFromUri(
}
/**
+ * Gather information about bank accounts that can be used for
+ * withdrawals. This includes accounts that are in a different
+ * currency and require conversion.
+ */
+async function fetchWithdrawalAccountInfo(
+ ws: InternalWalletState,
+ req: {
+ exchangeDetails: ExchangeDetailsRecord;
+ instructedAmount: AmountJson;
+ reservePub?: string;
+ },
+): Promise<WithdrawalAccountInfo[]> {
+ const { exchangeDetails, instructedAmount } = req;
+ const withdrawalAccounts: WithdrawalAccountInfo[] = [];
+ for (let acct of exchangeDetails.wireInfo.accounts) {
+ let paytoUri: string;
+ let transferAmount: AmountString;
+ if (acct.conversion_url != null) {
+ const reqUrl = new URL("cashin-rate", acct.conversion_url);
+ reqUrl.searchParams.set(
+ "amount_credit",
+ Amounts.stringify(instructedAmount),
+ );
+ const httpResp = await ws.http.fetch(reqUrl.href);
+ const resp = await readSuccessResponseJsonOrThrow(
+ httpResp,
+ codecForCashinConversionResponse(),
+ );
+ paytoUri = acct.payto_uri;
+ transferAmount = resp.amount_debit;
+ if (req.reservePub) {
+ }
+ } else {
+ paytoUri = acct.payto_uri;
+ transferAmount = Amounts.stringify(instructedAmount);
+ }
+ paytoUri = addPaytoQueryParams(paytoUri, {
+ amount: Amounts.stringify(transferAmount),
+ });
+ if (req.reservePub != null) {
+ paytoUri = addPaytoQueryParams(paytoUri, {
+ message: `Taler Withdrawal ${req.reservePub}`,
+ });
+ }
+ const acctInfo: WithdrawalAccountInfo = {
+ paytoUri,
+ transferAmount,
+ };
+ withdrawalAccounts.push(acctInfo);
+ }
+ return withdrawalAccounts;
+}
+
+/**
* Create a manual withdrawal operation.
*
* Adds the corresponding exchange as a trusted exchange if it is neither
@@ -2582,15 +2652,39 @@ export async function createManualWithdrawal(
forcedDenomSel?: ForcedDenomSel;
},
): Promise<AcceptManualWithdrawalResult> {
+ const { exchangeBaseUrl } = req;
+ const amount = Amounts.parseOrThrow(req.amount);
+ const { exchangeDetails } = await ws.exchangeOps.updateExchangeFromUrl(
+ ws,
+ exchangeBaseUrl,
+ );
+
+ if (exchangeDetails.currency != amount.currency) {
+ throw Error(
+ "manual withdrawal with conversion from foreign currency is not yet supported",
+ );
+ }
+ const reserveKeyPair: EddsaKeypair = await ws.cryptoApi.createEddsaKeypair(
+ {},
+ );
+
+ const withdrawalAccountList = await fetchWithdrawalAccountInfo(ws, {
+ exchangeDetails,
+ instructedAmount: amount,
+ reservePub: reserveKeyPair.pub,
+ });
+
const withdrawalGroup = await internalCreateWithdrawalGroup(ws, {
amount: Amounts.jsonifyAmount(req.amount),
wgInfo: {
withdrawalType: WithdrawalRecordType.BankManual,
+ exchangeCreditAccounts: withdrawalAccountList,
},
exchangeBaseUrl: req.exchangeBaseUrl,
forcedDenomSel: req.forcedDenomSel,
restrictAge: req.restrictAge,
reserveStatus: WithdrawalGroupStatus.PendingQueryingStatus,
+ reserveKeyPair,
});
const withdrawalGroupId = withdrawalGroup.withdrawalGroupId;
@@ -2610,6 +2704,7 @@ export async function createManualWithdrawal(
return {
reservePub: withdrawalGroup.reservePub,
exchangePaytoUris: exchangePaytoUris,
+ withdrawalAccountsList: withdrawalAccountList,
transactionId,
};
}
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 0694aef8a..4472bdbad 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -1215,6 +1215,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
paytoUris: wi.exchangePaytoUris,
tosAccepted: wi.termsOfServiceAccepted,
ageRestrictionOptions: wi.ageRestrictionOptions,
+ withdrawalAccountList: wi.withdrawalAccountList,
numCoins,
};
return resp;