summaryrefslogtreecommitdiff
path: root/packages/taler-util/src/wallet-types.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-util/src/wallet-types.ts')
-rw-r--r--packages/taler-util/src/wallet-types.ts3356
1 files changed, 3356 insertions, 0 deletions
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
new file mode 100644
index 000000000..a52b3e6ba
--- /dev/null
+++ b/packages/taler-util/src/wallet-types.ts
@@ -0,0 +1,3356 @@
+/*
+ This file is part of GNU Taler
+ (C) 2015-2020 Taler Systems SA
+
+ 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Types used by clients of the wallet.
+ *
+ * These types are defined in a separate file make tree shaking easier, since
+ * some components use these types (via RPC) but do not depend on the wallet
+ * code directly.
+ *
+ * @author Florian Dold <dold@taler.net>
+ */
+
+/**
+ * Imports.
+ */
+import { AmountJson, codecForAmountString } from "./amounts.js";
+import { BackupRecovery } from "./backup-types.js";
+import {
+ Codec,
+ Context,
+ DecodingError,
+ buildCodecForObject,
+ buildCodecForUnion,
+ codecForAny,
+ codecForBoolean,
+ codecForConstString,
+ codecForEither,
+ codecForList,
+ codecForMap,
+ codecForNumber,
+ codecForString,
+ codecOptional,
+ renderContext,
+} from "./codec.js";
+import {
+ CurrencySpecification,
+ TemplateParams,
+ WithdrawalOperationStatus,
+} from "./index.js";
+import { VersionMatchResult } from "./libtool-version.js";
+import { PaytoUri } from "./payto.js";
+import { AgeCommitmentProof } from "./taler-crypto.js";
+import { TalerErrorCode } from "./taler-error-codes.js";
+import {
+ AccountRestriction,
+ AmountString,
+ AuditorDenomSig,
+ CoinEnvelope,
+ DenomKeyType,
+ DenominationPubKey,
+ EddsaPrivateKeyString,
+ ExchangeAuditor,
+ ExchangeWireAccount,
+ InternationalizedString,
+ MerchantContractTerms,
+ MerchantInfo,
+ PeerContractTerms,
+ UnblindedSignature,
+ codecForExchangeWireAccount,
+ codecForMerchantContractTerms,
+ codecForPeerContractTerms,
+} from "./taler-types.js";
+import {
+ AbsoluteTime,
+ TalerPreciseTimestamp,
+ TalerProtocolDuration,
+ TalerProtocolTimestamp,
+ codecForAbsoluteTime,
+ codecForPreciseTimestamp,
+ codecForTimestamp,
+} from "./time.js";
+import {
+ OrderShortInfo,
+ TransactionState,
+ TransactionType,
+} from "./transactions-types.js";
+
+/**
+ * Identifier for a transaction in the wallet.
+ */
+declare const __txId: unique symbol;
+export type TransactionIdStr = `txn:${string}:${string}` & { [__txId]: true };
+
+/**
+ * Identifier for a pending task in the wallet.
+ */
+declare const __pndId: unique symbol;
+export type PendingIdStr = `pnd:${string}:${string}` & { [__pndId]: true };
+
+declare const __tmbId: unique symbol;
+export type TombstoneIdStr = `tmb:${string}:${string}` & { [__tmbId]: true };
+
+function codecForTransactionIdStr(): Codec<TransactionIdStr> {
+ return {
+ decode(x: any, c?: Context): TransactionIdStr {
+ if (typeof x === "string" && x.startsWith("txn:")) {
+ return x as TransactionIdStr;
+ }
+ throw new DecodingError(
+ `expected string starting with "txn:" at ${renderContext(
+ c,
+ )} but got ${x}`,
+ );
+ },
+ };
+}
+
+function codecForPendingIdStr(): Codec<PendingIdStr> {
+ return {
+ decode(x: any, c?: Context): PendingIdStr {
+ if (typeof x === "string" && x.startsWith("txn:")) {
+ return x as PendingIdStr;
+ }
+ throw new DecodingError(
+ `expected string starting with "txn:" at ${renderContext(
+ c,
+ )} but got ${x}`,
+ );
+ },
+ };
+}
+
+function codecForTombstoneIdStr(): Codec<TombstoneIdStr> {
+ return {
+ decode(x: any, c?: Context): TombstoneIdStr {
+ if (typeof x === "string" && x.startsWith("tmb:")) {
+ return x as TombstoneIdStr;
+ }
+ throw new DecodingError(
+ `expected string starting with "tmb:" at ${renderContext(
+ c,
+ )} but got ${x}`,
+ );
+ },
+ };
+}
+
+/**
+ * Response for the create reserve request to the wallet.
+ */
+export class CreateReserveResponse {
+ /**
+ * Exchange URL where the bank should create the reserve.
+ * The URL is canonicalized in the response.
+ */
+ exchange: string;
+
+ /**
+ * Reserve public key of the newly created reserve.
+ */
+ reservePub: string;
+}
+
+export interface GetBalanceDetailRequest {
+ currency: string;
+}
+
+export const codecForGetBalanceDetailRequest =
+ (): Codec<GetBalanceDetailRequest> =>
+ buildCodecForObject<GetBalanceDetailRequest>()
+ .property("currency", codecForString())
+ .build("GetBalanceDetailRequest");
+
+/**
+ * How the amount should be interpreted in a transaction
+ * Effective = how the balance is change
+ * Raw = effective amount without fee
+ *
+ * Depending on the transaction, raw can be higher than effective
+ */
+export enum TransactionAmountMode {
+ Effective = "effective",
+ Raw = "raw",
+}
+
+export type GetPlanForOperationRequest =
+ | GetPlanForWithdrawRequest
+ | GetPlanForDepositRequest;
+// | GetPlanForPushDebitRequest
+// | GetPlanForPullCreditRequest
+// | GetPlanForPaymentRequest
+// | GetPlanForTipRequest
+// | GetPlanForRefundRequest
+// | GetPlanForPullDebitRequest
+// | GetPlanForPushCreditRequest;
+
+interface GetPlanForWalletInitiatedOperation {
+ instructedAmount: AmountString;
+ mode: TransactionAmountMode;
+}
+
+export interface ConvertAmountRequest {
+ amount: AmountString;
+ type: TransactionAmountMode;
+}
+
+export const codecForConvertAmountRequest =
+ buildCodecForObject<ConvertAmountRequest>()
+ .property("amount", codecForAmountString())
+ .property(
+ "type",
+ codecForEither(
+ codecForConstString(TransactionAmountMode.Raw),
+ codecForConstString(TransactionAmountMode.Effective),
+ ),
+ )
+ .build("ConvertAmountRequest");
+
+export interface GetAmountRequest {
+ currency: string;
+}
+
+export const codecForGetAmountRequest = buildCodecForObject<GetAmountRequest>()
+ .property("currency", codecForString())
+ .build("GetAmountRequest");
+
+interface GetPlanToCompleteOperation {
+ instructedAmount: AmountString;
+}
+
+const codecForGetPlanForWalletInitiatedOperation = <
+ T extends GetPlanForWalletInitiatedOperation,
+>() =>
+ buildCodecForObject<T>()
+ .property(
+ "mode",
+ codecForEither(
+ codecForConstString(TransactionAmountMode.Raw),
+ codecForConstString(TransactionAmountMode.Effective),
+ ),
+ )
+ .property("instructedAmount", codecForAmountString());
+
+interface GetPlanForWithdrawRequest extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.Withdrawal;
+ exchangeUrl?: string;
+}
+interface GetPlanForDepositRequest extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.Deposit;
+ account: string; //payto string
+}
+interface GetPlanForPushDebitRequest
+ extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.PeerPushDebit;
+}
+
+interface GetPlanForPullCreditRequest
+ extends GetPlanForWalletInitiatedOperation {
+ type: TransactionType.PeerPullCredit;
+ exchangeUrl: string;
+}
+
+const codecForGetPlanForWithdrawRequest =
+ codecForGetPlanForWalletInitiatedOperation<GetPlanForWithdrawRequest>()
+ .property("type", codecForConstString(TransactionType.Withdrawal))
+ .property("exchangeUrl", codecOptional(codecForString()))
+ .build("GetPlanForWithdrawRequest");
+
+const codecForGetPlanForDepositRequest =
+ codecForGetPlanForWalletInitiatedOperation<GetPlanForDepositRequest>()
+ .property("type", codecForConstString(TransactionType.Deposit))
+ .property("account", codecForString())
+ .build("GetPlanForDepositRequest");
+
+const codecForGetPlanForPushDebitRequest =
+ codecForGetPlanForWalletInitiatedOperation<GetPlanForPushDebitRequest>()
+ .property("type", codecForConstString(TransactionType.PeerPushDebit))
+ .build("GetPlanForPushDebitRequest");
+
+const codecForGetPlanForPullCreditRequest =
+ codecForGetPlanForWalletInitiatedOperation<GetPlanForPullCreditRequest>()
+ .property("type", codecForConstString(TransactionType.PeerPullCredit))
+ .property("exchangeUrl", codecForString())
+ .build("GetPlanForPullCreditRequest");
+
+interface GetPlanForPaymentRequest extends GetPlanToCompleteOperation {
+ type: TransactionType.Payment;
+ wireMethod: string;
+ ageRestriction: number;
+ maxDepositFee: AmountString;
+}
+
+// interface GetPlanForTipRequest extends GetPlanForOperationBase {
+// type: TransactionType.Tip;
+// }
+// interface GetPlanForRefundRequest extends GetPlanForOperationBase {
+// type: TransactionType.Refund;
+// }
+interface GetPlanForPullDebitRequest extends GetPlanToCompleteOperation {
+ type: TransactionType.PeerPullDebit;
+}
+interface GetPlanForPushCreditRequest extends GetPlanToCompleteOperation {
+ type: TransactionType.PeerPushCredit;
+}
+
+const codecForGetPlanForPaymentRequest =
+ buildCodecForObject<GetPlanForPaymentRequest>()
+ .property("type", codecForConstString(TransactionType.Payment))
+ .property("maxDepositFee", codecForAmountString())
+ .build("GetPlanForPaymentRequest");
+
+const codecForGetPlanForPullDebitRequest =
+ buildCodecForObject<GetPlanForPullDebitRequest>()
+ .property("type", codecForConstString(TransactionType.PeerPullDebit))
+ .build("GetPlanForPullDebitRequest");
+
+const codecForGetPlanForPushCreditRequest =
+ buildCodecForObject<GetPlanForPushCreditRequest>()
+ .property("type", codecForConstString(TransactionType.PeerPushCredit))
+ .build("GetPlanForPushCreditRequest");
+
+export const codecForGetPlanForOperationRequest =
+ (): Codec<GetPlanForOperationRequest> =>
+ buildCodecForUnion<GetPlanForOperationRequest>()
+ .discriminateOn("type")
+ .alternative(
+ TransactionType.Withdrawal,
+ codecForGetPlanForWithdrawRequest,
+ )
+ .alternative(TransactionType.Deposit, codecForGetPlanForDepositRequest)
+ // .alternative(
+ // TransactionType.PeerPushDebit,
+ // codecForGetPlanForPushDebitRequest,
+ // )
+ // .alternative(
+ // TransactionType.PeerPullCredit,
+ // codecForGetPlanForPullCreditRequest,
+ // )
+ // .alternative(TransactionType.Payment, codecForGetPlanForPaymentRequest)
+ // .alternative(
+ // TransactionType.PeerPullDebit,
+ // codecForGetPlanForPullDebitRequest,
+ // )
+ // .alternative(
+ // TransactionType.PeerPushCredit,
+ // codecForGetPlanForPushCreditRequest,
+ // )
+ .build("GetPlanForOperationRequest");
+
+export interface GetPlanForOperationResponse {
+ effectiveAmount: AmountString;
+ rawAmount: AmountString;
+ counterPartyAmount?: AmountString;
+ details: any;
+}
+
+export const codecForGetPlanForOperationResponse =
+ (): Codec<GetPlanForOperationResponse> =>
+ buildCodecForObject<GetPlanForOperationResponse>()
+ .property("effectiveAmount", codecForAmountString())
+ .property("rawAmount", codecForAmountString())
+ .property("details", codecForAny())
+ .property("counterPartyAmount", codecOptional(codecForAmountString()))
+ .build("GetPlanForOperationResponse");
+
+export interface AmountResponse {
+ effectiveAmount: AmountString;
+ rawAmount: AmountString;
+}
+
+export const codecForAmountResponse = (): Codec<AmountResponse> =>
+ buildCodecForObject<AmountResponse>()
+ .property("effectiveAmount", codecForAmountString())
+ .property("rawAmount", codecForAmountString())
+ .build("AmountResponse");
+
+export enum BalanceFlag {
+ IncomingKyc = "incoming-kyc",
+ IncomingAml = "incoming-aml",
+ IncomingConfirmation = "incoming-confirmation",
+ OutgoingKyc = "outgoing-kyc",
+}
+
+export interface WalletBalance {
+ scopeInfo: ScopeInfo;
+ available: AmountString;
+ pendingIncoming: AmountString;
+ pendingOutgoing: AmountString;
+
+ /**
+ * Does the balance for this currency have a pending
+ * transaction?
+ *
+ * @deprecated use flags and pendingIncoming/pendingOutgoing instead
+ */
+ hasPendingTransactions: boolean;
+
+ /**
+ * Is there a transaction that requires user input?
+ *
+ * @deprecated use flags instead
+ */
+ requiresUserInput: boolean;
+
+ flags: BalanceFlag[];
+}
+
+export const codecForScopeInfoGlobal = (): Codec<ScopeInfoGlobal> =>
+ buildCodecForObject<ScopeInfoGlobal>()
+ .property("currency", codecForString())
+ .property("type", codecForConstString(ScopeType.Global))
+ .build("ScopeInfoGlobal");
+
+export const codecForScopeInfoExchange = (): Codec<ScopeInfoExchange> =>
+ buildCodecForObject<ScopeInfoExchange>()
+ .property("currency", codecForString())
+ .property("type", codecForConstString(ScopeType.Exchange))
+ .property("url", codecForString())
+ .build("ScopeInfoExchange");
+
+export const codecForScopeInfoAuditor = (): Codec<ScopeInfoAuditor> =>
+ buildCodecForObject<ScopeInfoAuditor>()
+ .property("currency", codecForString())
+ .property("type", codecForConstString(ScopeType.Auditor))
+ .property("url", codecForString())
+ .build("ScopeInfoAuditor");
+
+export const codecForScopeInfo = (): Codec<ScopeInfo> =>
+ buildCodecForUnion<ScopeInfo>()
+ .discriminateOn("type")
+ .alternative(ScopeType.Global, codecForScopeInfoGlobal())
+ .alternative(ScopeType.Exchange, codecForScopeInfoExchange())
+ .alternative(ScopeType.Auditor, codecForScopeInfoAuditor())
+ .build("ScopeInfo");
+
+export interface GetCurrencySpecificationRequest {
+ scope: ScopeInfo;
+}
+
+export const codecForGetCurrencyInfoRequest =
+ (): Codec<GetCurrencySpecificationRequest> =>
+ buildCodecForObject<GetCurrencySpecificationRequest>()
+ .property("scope", codecForScopeInfo())
+ .build("GetCurrencySpecificationRequest");
+
+export interface ListExchangesForScopedCurrencyRequest {
+ scope: ScopeInfo;
+}
+
+export const codecForListExchangesForScopedCurrencyRequest =
+ (): Codec<ListExchangesForScopedCurrencyRequest> =>
+ buildCodecForObject<ListExchangesForScopedCurrencyRequest>()
+ .property("scope", codecForScopeInfo())
+ .build("ListExchangesForScopedCurrencyRequest");
+
+export interface GetCurrencySpecificationResponse {
+ currencySpecification: CurrencySpecification;
+}
+
+export interface BuiltinExchange {
+ exchangeBaseUrl: string;
+ currencyHint: string;
+}
+
+export interface PartialWalletRunConfig {
+ builtin?: Partial<WalletRunConfig["builtin"]>;
+ testing?: Partial<WalletRunConfig["testing"]>;
+ features?: Partial<WalletRunConfig["features"]>;
+}
+
+export interface WalletRunConfig {
+ /**
+ * Initialization values useful for a complete startup.
+ *
+ * These are values may be overridden by different wallets
+ */
+ builtin: {
+ exchanges: BuiltinExchange[];
+ };
+
+ /**
+ * Unsafe options which it should only be used to create
+ * testing environment.
+ */
+ testing: {
+ /**
+ * Allow withdrawal of denominations even though they are about to expire.
+ */
+ denomselAllowLate: boolean;
+ devModeActive: boolean;
+ insecureTrustExchange: boolean;
+ preventThrottling: boolean;
+ skipDefaults: boolean;
+ emitObservabilityEvents?: boolean;
+ };
+
+ /**
+ * Configurations values that may be safe to show to the user
+ */
+ features: {
+ allowHttp: boolean;
+ };
+}
+
+export interface InitRequest {
+ config?: PartialWalletRunConfig;
+}
+
+export const codecForInitRequest = (): Codec<InitRequest> =>
+ buildCodecForObject<InitRequest>()
+ .property("config", codecForAny())
+ .build("InitRequest");
+
+export interface InitResponse {
+ versionInfo: WalletCoreVersion;
+}
+
+export enum ScopeType {
+ Global = "global",
+ Exchange = "exchange",
+ Auditor = "auditor",
+}
+
+export type ScopeInfoGlobal = { type: ScopeType.Global; currency: string };
+export type ScopeInfoExchange = {
+ type: ScopeType.Exchange;
+ currency: string;
+ url: string;
+};
+export type ScopeInfoAuditor = {
+ type: ScopeType.Auditor;
+ currency: string;
+ url: string;
+};
+
+export type ScopeInfo = ScopeInfoGlobal | ScopeInfoExchange | ScopeInfoAuditor;
+
+export interface BalancesResponse {
+ balances: WalletBalance[];
+}
+
+export const codecForBalance = (): Codec<WalletBalance> =>
+ buildCodecForObject<WalletBalance>()
+ .property("scopeInfo", codecForAny()) // FIXME
+ .property("available", codecForAmountString())
+ .property("hasPendingTransactions", codecForBoolean())
+ .property("pendingIncoming", codecForAmountString())
+ .property("pendingOutgoing", codecForAmountString())
+ .property("requiresUserInput", codecForBoolean())
+ .property("flags", codecForAny()) // FIXME
+ .build("Balance");
+
+export const codecForBalancesResponse = (): Codec<BalancesResponse> =>
+ buildCodecForObject<BalancesResponse>()
+ .property("balances", codecForList(codecForBalance()))
+ .build("BalancesResponse");
+
+/**
+ * For terseness.
+ */
+export function mkAmount(
+ value: number,
+ fraction: number,
+ currency: string,
+): AmountJson {
+ return { value, fraction, currency };
+}
+
+/**
+ * Status of a coin.
+ */
+export enum CoinStatus {
+ /**
+ * Withdrawn and never shown to anybody.
+ */
+ Fresh = "fresh",
+
+ /**
+ * Coin was lost as the denomination is not usable anymore.
+ */
+ DenomLoss = "denom-loss",
+
+ /**
+ * Fresh, but currently marked as "suspended", thus won't be used
+ * for spending. Used for testing.
+ */
+ FreshSuspended = "fresh-suspended",
+
+ /**
+ * A coin that has been spent and refreshed.
+ */
+ Dormant = "dormant",
+}
+
+/**
+ * Easy to process format for the public data of coins
+ * managed by the wallet.
+ */
+export interface CoinDumpJson {
+ coins: Array<{
+ /**
+ * The coin's denomination's public key.
+ */
+ denom_pub: DenominationPubKey;
+ /**
+ * Hash of denom_pub.
+ */
+ denom_pub_hash: string;
+ /**
+ * Value of the denomination (without any fees).
+ */
+ denom_value: string;
+ /**
+ * Public key of the coin.
+ */
+ coin_pub: string;
+ /**
+ * Base URL of the exchange for the coin.
+ */
+ exchange_base_url: string;
+ /**
+ * Public key of the parent coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ refresh_parent_coin_pub: string | undefined;
+ /**
+ * Public key of the reserve for this coin.
+ * Only present if this coin was obtained via refreshing.
+ */
+ withdrawal_reserve_pub: string | undefined;
+ coin_status: CoinStatus;
+ spend_allocation:
+ | {
+ id: string;
+ amount: AmountString;
+ }
+ | undefined;
+ /**
+ * Information about the age restriction
+ */
+ ageCommitmentProof: AgeCommitmentProof | undefined;
+ }>;
+}
+
+export enum ConfirmPayResultType {
+ Done = "done",
+ Pending = "pending",
+}
+
+/**
+ * Result for confirmPay
+ */
+export interface ConfirmPayResultDone {
+ type: ConfirmPayResultType.Done;
+ contractTerms: MerchantContractTerms;
+ transactionId: TransactionIdStr;
+}
+
+export interface ConfirmPayResultPending {
+ type: ConfirmPayResultType.Pending;
+ transactionId: TransactionIdStr;
+ lastError: TalerErrorDetail | undefined;
+}
+
+export const codecForTalerErrorDetail = (): Codec<TalerErrorDetail> =>
+ buildCodecForObject<TalerErrorDetail>()
+ .property("code", codecForNumber())
+ .property("when", codecOptional(codecForAbsoluteTime))
+ .property("hint", codecOptional(codecForString()))
+ .build("TalerErrorDetail");
+
+export type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending;
+
+export const codecForConfirmPayResultPending =
+ (): Codec<ConfirmPayResultPending> =>
+ buildCodecForObject<ConfirmPayResultPending>()
+ .property("lastError", codecOptional(codecForTalerErrorDetail()))
+ .property("transactionId", codecForTransactionIdStr())
+ .property("type", codecForConstString(ConfirmPayResultType.Pending))
+ .build("ConfirmPayResultPending");
+
+export const codecForConfirmPayResultDone = (): Codec<ConfirmPayResultDone> =>
+ buildCodecForObject<ConfirmPayResultDone>()
+ .property("type", codecForConstString(ConfirmPayResultType.Done))
+ .property("transactionId", codecForTransactionIdStr())
+ .property("contractTerms", codecForMerchantContractTerms())
+ .build("ConfirmPayResultDone");
+
+export const codecForConfirmPayResult = (): Codec<ConfirmPayResult> =>
+ buildCodecForUnion<ConfirmPayResult>()
+ .discriminateOn("type")
+ .alternative(
+ ConfirmPayResultType.Pending,
+ codecForConfirmPayResultPending(),
+ )
+ .alternative(ConfirmPayResultType.Done, codecForConfirmPayResultDone())
+ .build("ConfirmPayResult");
+
+/**
+ * Information about all sender wire details known to the wallet,
+ * as well as exchanges that accept these wire types.
+ */
+export interface SenderWireInfos {
+ /**
+ * Mapping from exchange base url to list of accepted
+ * wire types.
+ */
+ exchangeWireTypes: { [exchangeBaseUrl: string]: string[] };
+
+ /**
+ * Sender wire information stored in the wallet.
+ */
+ senderWires: string[];
+}
+
+/**
+ * Request to mark a reserve as confirmed.
+ */
+export interface ConfirmReserveRequest {
+ /**
+ * Public key of then reserve that should be marked
+ * as confirmed.
+ */
+ reservePub: string;
+}
+
+export const codecForConfirmReserveRequest = (): Codec<ConfirmReserveRequest> =>
+ buildCodecForObject<ConfirmReserveRequest>()
+ .property("reservePub", codecForString())
+ .build("ConfirmReserveRequest");
+
+export interface PrepareRefundResult {
+ proposalId: string;
+
+ effectivePaid: AmountString;
+ gone: AmountString;
+ granted: AmountString;
+ pending: boolean;
+ awaiting: AmountString;
+
+ info: OrderShortInfo;
+}
+
+export interface PrepareTipResult {
+ /**
+ * Unique ID for the tip assigned by the wallet.
+ * Typically different from the merchant-generated tip ID.
+ *
+ * @deprecated use transactionId instead
+ */
+ walletRewardId: string;
+
+ /**
+ * Tip transaction ID.
+ */
+ transactionId: TransactionIdStr;
+
+ /**
+ * Has the tip already been accepted?
+ */
+ accepted: boolean;
+
+ /**
+ * Amount that the merchant gave.
+ */
+ rewardAmountRaw: AmountString;
+
+ /**
+ * Amount that arrived at the wallet.
+ * Might be lower than the raw amount due to fees.
+ */
+ rewardAmountEffective: AmountString;
+
+ /**
+ * Base URL of the merchant backend giving then tip.
+ */
+ merchantBaseUrl: string;
+
+ /**
+ * Base URL of the exchange that is used to withdraw the tip.
+ * Determined by the merchant, the wallet/user has no choice here.
+ */
+ exchangeBaseUrl: string;
+
+ /**
+ * Time when the tip will expire. After it expired, it can't be picked
+ * up anymore.
+ */
+ expirationTimestamp: TalerProtocolTimestamp;
+}
+
+export interface AcceptTipResponse {
+ transactionId: TransactionIdStr;
+ next_url?: string;
+}
+
+export const codecForPrepareTipResult = (): Codec<PrepareTipResult> =>
+ buildCodecForObject<PrepareTipResult>()
+ .property("accepted", codecForBoolean())
+ .property("rewardAmountRaw", codecForAmountString())
+ .property("rewardAmountEffective", codecForAmountString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("merchantBaseUrl", codecForString())
+ .property("expirationTimestamp", codecForTimestamp)
+ .property("walletRewardId", codecForString())
+ .property("transactionId", codecForTransactionIdStr())
+ .build("PrepareRewardResult");
+
+export interface BenchmarkResult {
+ time: { [s: string]: number };
+ repetitions: number;
+}
+
+export enum PreparePayResultType {
+ PaymentPossible = "payment-possible",
+ InsufficientBalance = "insufficient-balance",
+ AlreadyConfirmed = "already-confirmed",
+}
+
+export const codecForPreparePayResultPaymentPossible =
+ (): Codec<PreparePayResultPaymentPossible> =>
+ buildCodecForObject<PreparePayResultPaymentPossible>()
+ .property("amountEffective", codecForAmountString())
+ .property("amountRaw", codecForAmountString())
+ .property("contractTerms", codecForMerchantContractTerms())
+ .property("transactionId", codecForTransactionIdStr())
+ .property("proposalId", codecForString())
+ .property("contractTermsHash", codecForString())
+ .property("talerUri", codecForString())
+ .property(
+ "status",
+ codecForConstString(PreparePayResultType.PaymentPossible),
+ )
+ .build("PreparePayResultPaymentPossible");
+
+export interface BalanceDetails {}
+
+/**
+ * Detailed reason for why the wallet's balance is insufficient.
+ */
+export interface PaymentInsufficientBalanceDetails {
+ /**
+ * Amount requested by the merchant.
+ */
+ amountRequested: AmountString;
+
+ /**
+ * Balance of type "available" (see balance.ts for definition).
+ */
+ balanceAvailable: AmountString;
+
+ /**
+ * Balance of type "material" (see balance.ts for definition).
+ */
+ balanceMaterial: AmountString;
+
+ /**
+ * Balance of type "age-acceptable" (see balance.ts for definition).
+ */
+ balanceAgeAcceptable: AmountString;
+
+ /**
+ * Balance of type "merchant-acceptable" (see balance.ts for definition).
+ */
+ balanceReceiverAcceptable: AmountString;
+
+ /**
+ * Balance of type "merchant-depositable" (see balance.ts for definition).
+ */
+ balanceReceiverDepositable: AmountString;
+
+ balanceExchangeDepositable: AmountString;
+
+ /**
+ * Maximum effective amount that the wallet can spend,
+ * when all fees are paid by the wallet.
+ */
+ maxEffectiveSpendAmount: AmountString;
+
+ perExchange: {
+ [url: string]: {
+ balanceAvailable: AmountString;
+ balanceMaterial: AmountString;
+ balanceExchangeDepositable: AmountString;
+ balanceAgeAcceptable: AmountString;
+ balanceReceiverAcceptable: AmountString;
+ balanceReceiverDepositable: AmountString;
+ maxEffectiveSpendAmount: AmountString;
+ /**
+ * Exchange doesn't have global fees configured for the relevant year,
+ * p2p payments aren't possible.
+ */
+ missingGlobalFees: boolean;
+ };
+ };
+}
+
+export const codecForPayMerchantInsufficientBalanceDetails =
+ (): Codec<PaymentInsufficientBalanceDetails> =>
+ buildCodecForObject<PaymentInsufficientBalanceDetails>()
+ .property("amountRequested", codecForAmountString())
+ .property("balanceAgeAcceptable", codecForAmountString())
+ .property("balanceAvailable", codecForAmountString())
+ .property("balanceMaterial", codecForAmountString())
+ .property("balanceReceiverAcceptable", codecForAmountString())
+ .property("balanceReceiverDepositable", codecForAmountString())
+ .property("balanceExchangeDepositable", codecForAmountString())
+ .property("perExchange", codecForAny())
+ .property("maxEffectiveSpendAmount", codecForAmountString())
+ .build("PayMerchantInsufficientBalanceDetails");
+
+export const codecForPreparePayResultInsufficientBalance =
+ (): Codec<PreparePayResultInsufficientBalance> =>
+ buildCodecForObject<PreparePayResultInsufficientBalance>()
+ .property("amountRaw", codecForAmountString())
+ .property("contractTerms", codecForAny())
+ .property("talerUri", codecForString())
+ .property("proposalId", codecForString())
+ .property("transactionId", codecForTransactionIdStr())
+ .property(
+ "status",
+ codecForConstString(PreparePayResultType.InsufficientBalance),
+ )
+ .property(
+ "balanceDetails",
+ codecForPayMerchantInsufficientBalanceDetails(),
+ )
+ .build("PreparePayResultInsufficientBalance");
+
+export const codecForPreparePayResultAlreadyConfirmed =
+ (): Codec<PreparePayResultAlreadyConfirmed> =>
+ buildCodecForObject<PreparePayResultAlreadyConfirmed>()
+ .property(
+ "status",
+ codecForConstString(PreparePayResultType.AlreadyConfirmed),
+ )
+ .property("amountEffective", codecOptional(codecForAmountString()))
+ .property("amountRaw", codecForAmountString())
+ .property("paid", codecForBoolean())
+ .property("talerUri", codecForString())
+ .property("contractTerms", codecForAny())
+ .property("contractTermsHash", codecForString())
+ .property("transactionId", codecForTransactionIdStr())
+ .property("proposalId", codecForString())
+ .build("PreparePayResultAlreadyConfirmed");
+
+export const codecForPreparePayResult = (): Codec<PreparePayResult> =>
+ buildCodecForUnion<PreparePayResult>()
+ .discriminateOn("status")
+ .alternative(
+ PreparePayResultType.AlreadyConfirmed,
+ codecForPreparePayResultAlreadyConfirmed(),
+ )
+ .alternative(
+ PreparePayResultType.InsufficientBalance,
+ codecForPreparePayResultInsufficientBalance(),
+ )
+ .alternative(
+ PreparePayResultType.PaymentPossible,
+ codecForPreparePayResultPaymentPossible(),
+ )
+ .build("PreparePayResult");
+
+/**
+ * Result of a prepare pay operation.
+ */
+export type PreparePayResult =
+ | PreparePayResultInsufficientBalance
+ | PreparePayResultAlreadyConfirmed
+ | PreparePayResultPaymentPossible;
+
+/**
+ * Payment is possible.
+ */
+export interface PreparePayResultPaymentPossible {
+ status: PreparePayResultType.PaymentPossible;
+ transactionId: TransactionIdStr;
+ /**
+ * @deprecated use transactionId instead
+ */
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ contractTermsHash: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ talerUri: string;
+}
+
+export interface PreparePayResultInsufficientBalance {
+ status: PreparePayResultType.InsufficientBalance;
+ transactionId: TransactionIdStr;
+ /**
+ * @deprecated use transactionId
+ */
+ proposalId: string;
+ contractTerms: MerchantContractTerms;
+ amountRaw: AmountString;
+ talerUri: string;
+ balanceDetails: PaymentInsufficientBalanceDetails;
+}
+
+export interface PreparePayResultAlreadyConfirmed {
+ status: PreparePayResultType.AlreadyConfirmed;
+ transactionId: TransactionIdStr;
+ contractTerms: MerchantContractTerms;
+ paid: boolean;
+ amountRaw: AmountString;
+ amountEffective: AmountString | undefined;
+ contractTermsHash: string;
+ /**
+ * @deprecated use transactionId
+ */
+ proposalId: string;
+ talerUri: string;
+}
+
+export interface BankWithdrawDetails {
+ status: WithdrawalOperationStatus;
+ amount: AmountJson;
+ senderWire?: string;
+ suggestedExchange?: string;
+ confirmTransferUrl?: string;
+ wireTypes: string[];
+ operationId: string;
+ apiBaseUrl: string;
+}
+
+export interface AcceptWithdrawalResponse {
+ reservePub: string;
+ confirmTransferUrl?: string;
+ transactionId: TransactionIdStr;
+}
+
+/**
+ * Details about a purchase, including refund status.
+ */
+export interface PurchaseDetails {
+ contractTerms: Record<string, undefined>;
+ hasRefund: boolean;
+ totalRefundAmount: AmountJson;
+ totalRefundAndRefreshFees: AmountJson;
+}
+
+export interface WalletDiagnostics {
+ walletManifestVersion: string;
+ walletManifestDisplayVersion: string;
+ errors: string[];
+ firefoxIdbProblem: boolean;
+ dbOutdated: boolean;
+}
+
+export interface TalerErrorDetail {
+ code: TalerErrorCode;
+ when?: AbsoluteTime;
+ hint?: string;
+ [x: string]: unknown;
+}
+
+/**
+ * Minimal information needed about a planchet for unblinding a signature.
+ *
+ * Can be a withdrawal/tipping/refresh planchet.
+ */
+export interface PlanchetUnblindInfo {
+ denomPub: DenominationPubKey;
+ blindingKey: string;
+}
+
+export interface WithdrawalPlanchet {
+ coinPub: string;
+ coinPriv: string;
+ reservePub: string;
+ denomPubHash: string;
+ denomPub: DenominationPubKey;
+ blindingKey: string;
+ withdrawSig: string;
+ coinEv: CoinEnvelope;
+ coinValue: AmountJson;
+ coinEvHash: string;
+ ageCommitmentProof?: AgeCommitmentProof;
+}
+
+export interface PlanchetCreationRequest {
+ secretSeed: string;
+ coinIndex: number;
+ value: AmountJson;
+ feeWithdraw: AmountJson;
+ denomPub: DenominationPubKey;
+ reservePub: string;
+ reservePriv: string;
+ restrictAge?: number;
+}
+
+/**
+ * Reasons for why a coin is being refreshed.
+ */
+export enum RefreshReason {
+ Manual = "manual",
+ PayMerchant = "pay-merchant",
+ PayDeposit = "pay-deposit",
+ PayPeerPush = "pay-peer-push",
+ PayPeerPull = "pay-peer-pull",
+ Refund = "refund",
+ AbortPay = "abort-pay",
+ AbortDeposit = "abort-deposit",
+ AbortPeerPushDebit = "abort-peer-push-debit",
+ AbortPeerPullDebit = "abort-peer-pull-debit",
+ Recoup = "recoup",
+ BackupRestored = "backup-restored",
+ Scheduled = "scheduled",
+}
+
+/**
+ * Request to refresh a single coin.
+ */
+export interface CoinRefreshRequest {
+ readonly coinPub: string;
+ readonly amount: AmountString;
+}
+
+/**
+ * Private data required to make a deposit permission.
+ */
+export interface DepositInfo {
+ exchangeBaseUrl: string;
+ contractTermsHash: string;
+ coinPub: string;
+ coinPriv: string;
+ spendAmount: AmountJson;
+ timestamp: TalerProtocolTimestamp;
+ refundDeadline: TalerProtocolTimestamp;
+ merchantPub: string;
+ feeDeposit: AmountJson;
+ wireInfoHash: string;
+ denomKeyType: DenomKeyType;
+ denomPubHash: string;
+ denomSig: UnblindedSignature;
+
+ requiredMinimumAge?: number;
+
+ ageCommitmentProof?: AgeCommitmentProof;
+}
+
+export interface ExchangesShortListResponse {
+ exchanges: ShortExchangeListItem[];
+}
+
+export interface ExchangesListResponse {
+ exchanges: ExchangeListItem[];
+}
+
+export interface ExchangeDetailedResponse {
+ exchange: ExchangeFullDetails;
+}
+
+export interface WalletCoreVersion {
+ implementationSemver: string;
+ implementationGitHash: string;
+
+ /**
+ * Wallet-core protocol version supported by this implementation
+ * of the API ("server" version).
+ */
+ version: string;
+ exchange: string;
+ merchant: string;
+
+ bankIntegrationApiRange: string;
+ bankConversionApiRange: string;
+ corebankApiRange: string;
+
+ /**
+ * @deprecated as bank was split into multiple APIs with separate versioning
+ */
+ bank: string;
+
+ /**
+ * @deprecated
+ */
+ hash: string | undefined;
+
+ /**
+ * @deprecated will be removed
+ */
+ devMode: boolean;
+}
+
+export interface KnownBankAccountsInfo {
+ uri: PaytoUri;
+ kyc_completed: boolean;
+ currency: string;
+ alias: string;
+}
+
+export interface KnownBankAccounts {
+ accounts: KnownBankAccountsInfo[];
+}
+
+/**
+ * Wire fee for one wire method
+ */
+export interface WireFee {
+ /**
+ * Fee for wire transfers.
+ */
+ wireFee: AmountString;
+
+ /**
+ * Fees to close and refund a reserve.
+ */
+ closingFee: AmountString;
+
+ /**
+ * Start date of the fee.
+ */
+ startStamp: TalerProtocolTimestamp;
+
+ /**
+ * End date of the fee.
+ */
+ endStamp: TalerProtocolTimestamp;
+
+ /**
+ * Signature made by the exchange master key.
+ */
+ sig: string;
+}
+
+export type WireFeeMap = { [wireMethod: string]: WireFee[] };
+
+export interface WireInfo {
+ feesForType: WireFeeMap;
+ accounts: ExchangeWireAccount[];
+}
+
+export interface ExchangeGlobalFees {
+ startDate: TalerProtocolTimestamp;
+ endDate: TalerProtocolTimestamp;
+
+ historyFee: AmountString;
+ accountFee: AmountString;
+ purseFee: AmountString;
+
+ historyTimeout: TalerProtocolDuration;
+ purseTimeout: TalerProtocolDuration;
+
+ purseLimit: number;
+
+ signature: string;
+}
+
+const codecForWireFee = (): Codec<WireFee> =>
+ buildCodecForObject<WireFee>()
+ .property("sig", codecForString())
+ .property("wireFee", codecForAmountString())
+ .property("closingFee", codecForAmountString())
+ .property("startStamp", codecForTimestamp)
+ .property("endStamp", codecForTimestamp)
+ .build("codecForWireFee");
+
+const codecForWireInfo = (): Codec<WireInfo> =>
+ buildCodecForObject<WireInfo>()
+ .property("feesForType", codecForMap(codecForList(codecForWireFee())))
+ .property("accounts", codecForList(codecForExchangeWireAccount()))
+ .build("codecForWireInfo");
+
+export interface DenominationInfo {
+ /**
+ * Value of one coin of the denomination.
+ */
+ value: AmountString;
+
+ /**
+ * Hash of the denomination public key.
+ * Stored in the database for faster lookups.
+ */
+ denomPubHash: string;
+
+ denomPub: DenominationPubKey;
+
+ /**
+ * Fee for withdrawing.
+ */
+ feeWithdraw: AmountString;
+
+ /**
+ * Fee for depositing.
+ */
+ feeDeposit: AmountString;
+
+ /**
+ * Fee for refreshing.
+ */
+ feeRefresh: AmountString;
+
+ /**
+ * Fee for refunding.
+ */
+ feeRefund: AmountString;
+
+ /**
+ * Validity start date of the denomination.
+ */
+ stampStart: TalerProtocolTimestamp;
+
+ /**
+ * Date after which the currency can't be withdrawn anymore.
+ */
+ stampExpireWithdraw: TalerProtocolTimestamp;
+
+ /**
+ * Date after the denomination officially doesn't exist anymore.
+ */
+ stampExpireLegal: TalerProtocolTimestamp;
+
+ /**
+ * Data after which coins of this denomination can't be deposited anymore.
+ */
+ stampExpireDeposit: TalerProtocolTimestamp;
+
+ exchangeBaseUrl: string;
+}
+
+export type DenomOperation = "deposit" | "withdraw" | "refresh" | "refund";
+export type DenomOperationMap<T> = { [op in DenomOperation]: T };
+
+export interface FeeDescription {
+ group: string;
+ from: AbsoluteTime;
+ until: AbsoluteTime;
+ fee?: AmountString;
+}
+
+export interface FeeDescriptionPair {
+ group: string;
+ from: AbsoluteTime;
+ until: AbsoluteTime;
+ left?: AmountString;
+ right?: AmountString;
+}
+
+export interface TimePoint<T> {
+ id: string;
+ group: string;
+ fee: AmountString;
+ type: "start" | "end";
+ moment: AbsoluteTime;
+ denom: T;
+}
+
+export interface ExchangeFullDetails {
+ exchangeBaseUrl: string;
+ currency: string;
+ paytoUris: string[];
+ auditors: ExchangeAuditor[];
+ wireInfo: WireInfo;
+ denomFees: DenomOperationMap<FeeDescription[]>;
+ transferFees: Record<string, FeeDescription[]>;
+ globalFees: FeeDescription[];
+}
+
+export enum ExchangeTosStatus {
+ Pending = "pending",
+ Proposed = "proposed",
+ Accepted = "accepted",
+}
+
+export enum ExchangeEntryStatus {
+ Preset = "preset",
+ Ephemeral = "ephemeral",
+ Used = "used",
+}
+
+export enum ExchangeUpdateStatus {
+ Initial = "initial",
+ InitialUpdate = "initial-update",
+ Suspended = "suspended",
+ UnavailableUpdate = "unavailable-update",
+ Ready = "ready",
+ ReadyUpdate = "ready-update",
+}
+
+export interface OperationErrorInfo {
+ error: TalerErrorDetail;
+}
+
+export interface ShortExchangeListItem {
+ exchangeBaseUrl: string;
+}
+
+/**
+ * Info about an exchange entry in the wallet.
+ */
+export interface ExchangeListItem {
+ exchangeBaseUrl: string;
+ masterPub: string | undefined;
+ currency: string;
+ paytoUris: string[];
+ tosStatus: ExchangeTosStatus;
+ exchangeEntryStatus: ExchangeEntryStatus;
+ exchangeUpdateStatus: ExchangeUpdateStatus;
+ ageRestrictionOptions: number[];
+
+ /**
+ * P2P payments are disabled with this exchange
+ * (e.g. because no global fees are configured).
+ */
+ peerPaymentsDisabled: boolean;
+
+ /**
+ * Set to true if this exchange doesn't charge any fees.
+ */
+ noFees: boolean;
+
+ scopeInfo: ScopeInfo;
+
+ lastUpdateTimestamp: TalerPreciseTimestamp | undefined;
+
+ /**
+ * Information about the last error that occurred when trying
+ * to update the exchange info.
+ */
+ lastUpdateErrorInfo?: OperationErrorInfo;
+}
+
+const codecForAuditorDenomSig = (): Codec<AuditorDenomSig> =>
+ buildCodecForObject<AuditorDenomSig>()
+ .property("denom_pub_h", codecForString())
+ .property("auditor_sig", codecForString())
+ .build("AuditorDenomSig");
+
+const codecForExchangeAuditor = (): Codec<ExchangeAuditor> =>
+ buildCodecForObject<ExchangeAuditor>()
+ .property("auditor_pub", codecForString())
+ .property("auditor_url", codecForString())
+ .property("denomination_keys", codecForList(codecForAuditorDenomSig()))
+ .build("codecForExchangeAuditor");
+
+export const codecForFeeDescriptionPair = (): Codec<FeeDescriptionPair> =>
+ buildCodecForObject<FeeDescriptionPair>()
+ .property("group", codecForString())
+ .property("from", codecForAbsoluteTime)
+ .property("until", codecForAbsoluteTime)
+ .property("left", codecOptional(codecForAmountString()))
+ .property("right", codecOptional(codecForAmountString()))
+ .build("FeeDescriptionPair");
+
+export const codecForFeeDescription = (): Codec<FeeDescription> =>
+ buildCodecForObject<FeeDescription>()
+ .property("group", codecForString())
+ .property("from", codecForAbsoluteTime)
+ .property("until", codecForAbsoluteTime)
+ .property("fee", codecOptional(codecForAmountString()))
+ .build("FeeDescription");
+
+export const codecForFeesByOperations = (): Codec<
+ DenomOperationMap<FeeDescription[]>
+> =>
+ buildCodecForObject<DenomOperationMap<FeeDescription[]>>()
+ .property("deposit", codecForList(codecForFeeDescription()))
+ .property("withdraw", codecForList(codecForFeeDescription()))
+ .property("refresh", codecForList(codecForFeeDescription()))
+ .property("refund", codecForList(codecForFeeDescription()))
+ .build("DenomOperationMap");
+
+export const codecForExchangeFullDetails = (): Codec<ExchangeFullDetails> =>
+ buildCodecForObject<ExchangeFullDetails>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("paytoUris", codecForList(codecForString()))
+ .property("auditors", codecForList(codecForExchangeAuditor()))
+ .property("wireInfo", codecForWireInfo())
+ .property("denomFees", codecForFeesByOperations())
+ .property(
+ "transferFees",
+ codecForMap(codecForList(codecForFeeDescription())),
+ )
+ .property("globalFees", codecForList(codecForFeeDescription()))
+ .build("ExchangeFullDetails");
+
+export const codecForExchangeListItem = (): Codec<ExchangeListItem> =>
+ buildCodecForObject<ExchangeListItem>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("masterPub", codecOptional(codecForString()))
+ .property("paytoUris", codecForList(codecForString()))
+ .property("tosStatus", codecForAny())
+ .property("exchangeEntryStatus", codecForAny())
+ .property("exchangeUpdateStatus", codecForAny())
+ .property("ageRestrictionOptions", codecForList(codecForNumber()))
+ .property("scopeInfo", codecForScopeInfo())
+ .property("lastUpdateErrorInfo", codecForAny())
+ .property("lastUpdateTimestamp", codecOptional(codecForPreciseTimestamp))
+ .property("noFees", codecForBoolean())
+ .property("peerPaymentsDisabled", codecForBoolean())
+ .build("ExchangeListItem");
+
+export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> =>
+ buildCodecForObject<ExchangesListResponse>()
+ .property("exchanges", codecForList(codecForExchangeListItem()))
+ .build("ExchangesListResponse");
+
+export interface AcceptManualWithdrawalResult {
+ /**
+ * Payto URIs that can be used to fund the withdrawal.
+ *
+ * @deprecated in favor of withdrawalAccountsList
+ */
+ exchangePaytoUris: string[];
+
+ /**
+ * Public key of the newly created reserve.
+ */
+ reservePub: string;
+
+ withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
+
+ transactionId: TransactionIdStr;
+}
+
+export interface WithdrawalDetailsForAmount {
+ /**
+ * Did the user accept the current version of the exchange's
+ * terms of service?
+ *
+ * @deprecated the client should query the exchange entry instead
+ */
+ tosAccepted: boolean;
+
+ /**
+ * Amount that the user will transfer to the exchange.
+ */
+ amountRaw: AmountString;
+
+ /**
+ * Amount that will be added to the user's wallet balance.
+ */
+ amountEffective: AmountString;
+
+ /**
+ * Number of coins that would be used for withdrawal.
+ *
+ * The UIs should warn if this number is too high (roughly at >100).
+ */
+ numCoins: number;
+
+ /**
+ * Ways to pay the exchange.
+ *
+ * @deprecated in favor of withdrawalAccountsList
+ */
+ paytoUris: string[];
+
+ /**
+ * Ways to pay the exchange, including accounts that require currency conversion.
+ */
+ withdrawalAccountsList: WithdrawalExchangeAccountDetails[];
+
+ /**
+ * If the exchange supports age-restricted coins it will return
+ * the array of ages.
+ */
+ ageRestrictionOptions?: number[];
+
+ /**
+ * Scope info of the currency withdrawn.
+ */
+ scopeInfo: ScopeInfo;
+}
+
+export interface DenomSelItem {
+ denomPubHash: string;
+ count: number;
+ /**
+ * Number of denoms/planchets to skip, because
+ * a re-denomination effectively deleted them.
+ */
+ skip?: number;
+}
+
+/**
+ * Selected denominations withn some extra info.
+ */
+export interface DenomSelectionState {
+ totalCoinValue: AmountString;
+ totalWithdrawCost: AmountString;
+ selectedDenoms: DenomSelItem[];
+ earliestDepositExpiration: TalerProtocolTimestamp;
+ hasDenomWithAgeRestriction: boolean;
+}
+
+/**
+ * Information about what will happen doing a withdrawal.
+ *
+ * Sent to the wallet frontend to be rendered and shown to the user.
+ */
+export interface ExchangeWithdrawalDetails {
+ exchangePaytoUris: string[];
+
+ /**
+ * Filtered wire info to send to the bank.
+ */
+ exchangeWireAccounts: string[];
+
+ exchangeCreditAccountDetails: WithdrawalExchangeAccountDetails[];
+
+ /**
+ * Selected denominations for withdraw.
+ */
+ selectedDenoms: DenomSelectionState;
+
+ /**
+ * Did the user already accept the current terms of service for the exchange?
+ */
+ termsOfServiceAccepted: boolean;
+
+ /**
+ * The earliest deposit expiration of the selected coins.
+ */
+ earliestDepositExpiration: TalerProtocolTimestamp;
+
+ /**
+ * Result of checking the wallet's version
+ * against the exchange's version.
+ *
+ * Older exchanges don't return version information.
+ */
+ versionMatch: VersionMatchResult | undefined;
+
+ /**
+ * Libtool-style version string for the exchange or "unknown"
+ * for older exchanges.
+ */
+ exchangeVersion: string;
+
+ /**
+ * Libtool-style version string for the wallet.
+ */
+ walletVersion: string;
+
+ /**
+ * Amount that will be subtracted from the reserve's balance.
+ */
+ withdrawalAmountRaw: AmountString;
+
+ /**
+ * Amount that will actually be added to the wallet's balance.
+ */
+ withdrawalAmountEffective: AmountString;
+
+ /**
+ * If the exchange supports age-restricted coins it will return
+ * the array of ages.
+ *
+ */
+ ageRestrictionOptions?: number[];
+
+ scopeInfo: ScopeInfo;
+}
+
+export interface GetExchangeTosResult {
+ /**
+ * Markdown version of the current ToS.
+ */
+ content: string;
+
+ /**
+ * Version tag of the current ToS.
+ */
+ currentEtag: string;
+
+ /**
+ * Version tag of the last ToS that the user has accepted,
+ * if any.
+ */
+ acceptedEtag: string | undefined;
+
+ /**
+ * Accepted content type
+ */
+ contentType: string;
+
+ /**
+ * Language of the returned content.
+ *
+ * If missing, language is unknown.
+ */
+ contentLanguage: string | undefined;
+
+ /**
+ * Available languages as advertised by the exchange.
+ */
+ tosAvailableLanguages: string[];
+
+ tosStatus: ExchangeTosStatus;
+}
+
+export interface TestPayArgs {
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amount: AmountString;
+ summary: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+export const codecForTestPayArgs = (): Codec<TestPayArgs> =>
+ buildCodecForObject<TestPayArgs>()
+ .property("merchantBaseUrl", codecForString())
+ .property("merchantAuthToken", codecOptional(codecForString()))
+ .property("amount", codecForAmountString())
+ .property("summary", codecForString())
+ .property("forcedCoinSel", codecForAny())
+ .build("TestPayArgs");
+
+export interface IntegrationTestArgs {
+ exchangeBaseUrl: string;
+ corebankApiBaseUrl: string;
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+ amountToWithdraw: AmountString;
+ amountToSpend: AmountString;
+}
+
+export const codecForIntegrationTestArgs = (): Codec<IntegrationTestArgs> =>
+ buildCodecForObject<IntegrationTestArgs>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("merchantBaseUrl", codecForString())
+ .property("merchantAuthToken", codecOptional(codecForString()))
+ .property("amountToSpend", codecForAmountString())
+ .property("amountToWithdraw", codecForAmountString())
+ .property("corebankApiBaseUrl", codecForString())
+ .build("IntegrationTestArgs");
+
+export interface IntegrationTestV2Args {
+ exchangeBaseUrl: string;
+ corebankApiBaseUrl: string;
+ merchantBaseUrl: string;
+ merchantAuthToken?: string;
+}
+
+export const codecForIntegrationTestV2Args = (): Codec<IntegrationTestV2Args> =>
+ buildCodecForObject<IntegrationTestV2Args>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("merchantBaseUrl", codecForString())
+ .property("merchantAuthToken", codecOptional(codecForString()))
+ .property("corebankApiBaseUrl", codecForString())
+ .build("IntegrationTestV2Args");
+
+export interface GetExchangeEntryByUrlRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForGetExchangeEntryByUrlRequest =
+ (): Codec<GetExchangeEntryByUrlRequest> =>
+ buildCodecForObject<GetExchangeEntryByUrlRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("GetExchangeEntryByUrlRequest");
+
+export type GetExchangeEntryByUrlResponse = ExchangeListItem;
+
+export interface AddExchangeRequest {
+ exchangeBaseUrl: string;
+
+ /**
+ * @deprecated use a separate API call to start a forced exchange update instead
+ */
+ forceUpdate?: boolean;
+
+ masterPub?: string;
+}
+
+export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
+ buildCodecForObject<AddExchangeRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("forceUpdate", codecOptional(codecForBoolean()))
+ .property("masterPub", codecOptional(codecForString()))
+ .build("AddExchangeRequest");
+
+export interface UpdateExchangeEntryRequest {
+ exchangeBaseUrl: string;
+ force?: boolean;
+}
+
+export const codecForUpdateExchangeEntryRequest =
+ (): Codec<UpdateExchangeEntryRequest> =>
+ buildCodecForObject<UpdateExchangeEntryRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("force", codecOptional(codecForBoolean()))
+ .build("UpdateExchangeEntryRequest");
+
+export interface GetExchangeResourcesRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForGetExchangeResourcesRequest =
+ (): Codec<GetExchangeResourcesRequest> =>
+ buildCodecForObject<GetExchangeResourcesRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("GetExchangeResourcesRequest");
+
+export interface GetExchangeResourcesResponse {
+ hasResources: boolean;
+}
+
+export interface DeleteExchangeRequest {
+ exchangeBaseUrl: string;
+ purge?: boolean;
+}
+
+export const codecForDeleteExchangeRequest = (): Codec<DeleteExchangeRequest> =>
+ buildCodecForObject<DeleteExchangeRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("purge", codecOptional(codecForBoolean()))
+ .build("DeleteExchangeRequest");
+
+export interface ForceExchangeUpdateRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForForceExchangeUpdateRequest =
+ (): Codec<AddExchangeRequest> =>
+ buildCodecForObject<AddExchangeRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("AddExchangeRequest");
+
+export interface GetExchangeTosRequest {
+ exchangeBaseUrl: string;
+ acceptedFormat?: string[];
+ acceptLanguage?: string;
+}
+
+export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
+ buildCodecForObject<GetExchangeTosRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("acceptedFormat", codecOptional(codecForList(codecForString())))
+ .property("acceptLanguage", codecOptional(codecForString()))
+ .build("GetExchangeTosRequest");
+
+export interface AcceptManualWithdrawalRequest {
+ exchangeBaseUrl: string;
+ amount: AmountString;
+ restrictAge?: number;
+
+ /**
+ * Instead of generating a fresh, random reserve key pair,
+ * use the provided reserve private key.
+ *
+ * Use with caution. Usage of this field may be restricted
+ * to developer mode.
+ */
+ forceReservePriv?: EddsaPrivateKeyString;
+}
+
+export const codecForAcceptManualWithdrawalRequest =
+ (): Codec<AcceptManualWithdrawalRequest> =>
+ buildCodecForObject<AcceptManualWithdrawalRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("amount", codecForAmountString())
+ .property("restrictAge", codecOptional(codecForNumber()))
+ .property("forceReservePriv", codecOptional(codecForString()))
+ .build("AcceptManualWithdrawalRequest");
+
+export interface GetWithdrawalDetailsForAmountRequest {
+ exchangeBaseUrl: string;
+ amount: AmountString;
+ restrictAge?: number;
+
+ /**
+ * ID provided by the client to cancel the request.
+ *
+ * If the same request is made again with the same clientCancellationId,
+ * all previous requests are cancelled.
+ *
+ * The cancelled request will receive an error response with
+ * an error code that indicates the cancellation.
+ *
+ * The cancellation is best-effort, responses might still arrive.
+ */
+ clientCancellationId?: string;
+}
+
+export interface PrepareBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+export const codecForPrepareBankIntegratedWithdrawalRequest =
+ (): Codec<PrepareBankIntegratedWithdrawalRequest> =>
+ buildCodecForObject<PrepareBankIntegratedWithdrawalRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("talerWithdrawUri", codecForString())
+ .property("forcedDenomSel", codecForAny())
+ .property("restrictAge", codecOptional(codecForNumber()))
+ .build("PrepareBankIntegratedWithdrawalRequest");
+
+export interface PrepareBankIntegratedWithdrawalResponse {
+ transactionId: string;
+}
+
+export interface ConfirmWithdrawalRequest {
+ transactionId: string;
+}
+
+export const codecForConfirmWithdrawalRequestRequest =
+ (): Codec<ConfirmWithdrawalRequest> =>
+ buildCodecForObject<ConfirmWithdrawalRequest>()
+ .property("transactionId", codecForString())
+ .build("ConfirmWithdrawalRequest");
+
+export interface AcceptBankIntegratedWithdrawalRequest {
+ talerWithdrawUri: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+ restrictAge?: number;
+}
+
+export const codecForAcceptBankIntegratedWithdrawalRequest =
+ (): Codec<AcceptBankIntegratedWithdrawalRequest> =>
+ buildCodecForObject<AcceptBankIntegratedWithdrawalRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("talerWithdrawUri", codecForString())
+ .property("forcedDenomSel", codecForAny())
+ .property("restrictAge", codecOptional(codecForNumber()))
+ .build("AcceptBankIntegratedWithdrawalRequest");
+
+export const codecForGetWithdrawalDetailsForAmountRequest =
+ (): Codec<GetWithdrawalDetailsForAmountRequest> =>
+ buildCodecForObject<GetWithdrawalDetailsForAmountRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .property("amount", codecForAmountString())
+ .property("restrictAge", codecOptional(codecForNumber()))
+ .property("clientCancellationId", codecOptional(codecForString()))
+ .build("GetWithdrawalDetailsForAmountRequest");
+
+export interface AcceptExchangeTosRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForAcceptExchangeTosRequest =
+ (): Codec<AcceptExchangeTosRequest> =>
+ buildCodecForObject<AcceptExchangeTosRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("AcceptExchangeTosRequest");
+
+export interface ForgetExchangeTosRequest {
+ exchangeBaseUrl: string;
+}
+
+export const codecForForgetExchangeTosRequest =
+ (): Codec<ForgetExchangeTosRequest> =>
+ buildCodecForObject<ForgetExchangeTosRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("ForgetExchangeTosRequest");
+
+export interface AcceptRefundRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForApplyRefundRequest = (): Codec<AcceptRefundRequest> =>
+ buildCodecForObject<AcceptRefundRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("AcceptRefundRequest");
+
+export interface ApplyRefundFromPurchaseIdRequest {
+ purchaseId: string;
+}
+
+export const codecForApplyRefundFromPurchaseIdRequest =
+ (): Codec<ApplyRefundFromPurchaseIdRequest> =>
+ buildCodecForObject<ApplyRefundFromPurchaseIdRequest>()
+ .property("purchaseId", codecForString())
+ .build("ApplyRefundFromPurchaseIdRequest");
+
+export interface GetWithdrawalDetailsForUriRequest {
+ talerWithdrawUri: string;
+ restrictAge?: number;
+}
+
+export const codecForGetWithdrawalDetailsForUri =
+ (): Codec<GetWithdrawalDetailsForUriRequest> =>
+ buildCodecForObject<GetWithdrawalDetailsForUriRequest>()
+ .property("talerWithdrawUri", codecForString())
+ .property("restrictAge", codecOptional(codecForNumber()))
+ .build("GetWithdrawalDetailsForUriRequest");
+
+export interface ListKnownBankAccountsRequest {
+ currency?: string;
+}
+
+export const codecForListKnownBankAccounts =
+ (): Codec<ListKnownBankAccountsRequest> =>
+ buildCodecForObject<ListKnownBankAccountsRequest>()
+ .property("currency", codecOptional(codecForString()))
+ .build("ListKnownBankAccountsRequest");
+
+export interface AddKnownBankAccountsRequest {
+ payto: string;
+ alias: string;
+ currency: string;
+}
+export const codecForAddKnownBankAccounts =
+ (): Codec<AddKnownBankAccountsRequest> =>
+ buildCodecForObject<AddKnownBankAccountsRequest>()
+ .property("payto", codecForString())
+ .property("alias", codecForString())
+ .property("currency", codecForString())
+ .build("AddKnownBankAccountsRequest");
+
+export interface ForgetKnownBankAccountsRequest {
+ payto: string;
+}
+
+export const codecForForgetKnownBankAccounts =
+ (): Codec<ForgetKnownBankAccountsRequest> =>
+ buildCodecForObject<ForgetKnownBankAccountsRequest>()
+ .property("payto", codecForString())
+ .build("ForgetKnownBankAccountsRequest");
+
+export interface AbortProposalRequest {
+ proposalId: string;
+}
+
+export const codecForAbortProposalRequest = (): Codec<AbortProposalRequest> =>
+ buildCodecForObject<AbortProposalRequest>()
+ .property("proposalId", codecForString())
+ .build("AbortProposalRequest");
+
+export interface GetContractTermsDetailsRequest {
+ // @deprecated use transaction id
+ proposalId?: string;
+ transactionId?: string;
+}
+
+export const codecForGetContractTermsDetails =
+ (): Codec<GetContractTermsDetailsRequest> =>
+ buildCodecForObject<GetContractTermsDetailsRequest>()
+ .property("proposalId", codecOptional(codecForString()))
+ .property("transactionId", codecOptional(codecForString()))
+ .build("GetContractTermsDetails");
+
+export interface PreparePayRequest {
+ talerPayUri: string;
+}
+
+export const codecForPreparePayRequest = (): Codec<PreparePayRequest> =>
+ buildCodecForObject<PreparePayRequest>()
+ .property("talerPayUri", codecForString())
+ .build("PreparePay");
+
+export interface SharePaymentRequest {
+ merchantBaseUrl: string;
+ orderId: string;
+}
+export const codecForSharePaymentRequest = (): Codec<SharePaymentRequest> =>
+ buildCodecForObject<SharePaymentRequest>()
+ .property("merchantBaseUrl", codecForString())
+ .property("orderId", codecForString())
+ .build("SharePaymentRequest");
+
+export interface SharePaymentResult {
+ privatePayUri: string;
+}
+export const codecForSharePaymentResult = (): Codec<SharePaymentResult> =>
+ buildCodecForObject<SharePaymentResult>()
+ .property("privatePayUri", codecForString())
+ .build("SharePaymentResult");
+
+export interface PreparePayTemplateRequest {
+ talerPayTemplateUri: string;
+ templateParams?: TemplateParams;
+}
+
+export const codecForPreparePayTemplateRequest =
+ (): Codec<PreparePayTemplateRequest> =>
+ buildCodecForObject<PreparePayTemplateRequest>()
+ .property("talerPayTemplateUri", codecForString())
+ .property("templateParams", codecForAny())
+ .build("PreparePayTemplate");
+
+export interface ConfirmPayRequest {
+ /**
+ * @deprecated use transactionId instead
+ */
+ proposalId?: string;
+ transactionId?: TransactionIdStr;
+ sessionId?: string;
+ forcedCoinSel?: ForcedCoinSel;
+}
+
+export const codecForConfirmPayRequest = (): Codec<ConfirmPayRequest> =>
+ buildCodecForObject<ConfirmPayRequest>()
+ .property("proposalId", codecOptional(codecForString()))
+ .property("transactionId", codecOptional(codecForTransactionIdStr()))
+ .property("sessionId", codecOptional(codecForString()))
+ .property("forcedCoinSel", codecForAny())
+ .build("ConfirmPay");
+
+export interface CoreApiRequestEnvelope {
+ id: string;
+ operation: string;
+ args: unknown;
+}
+
+export type CoreApiResponse = CoreApiResponseSuccess | CoreApiResponseError;
+
+export type CoreApiMessageEnvelope = CoreApiResponse | CoreApiNotification;
+
+export interface CoreApiNotification {
+ type: "notification";
+ payload: unknown;
+}
+
+export interface CoreApiResponseSuccess {
+ // To distinguish the message from notifications
+ type: "response";
+ operation: string;
+ id: string;
+ result: unknown;
+}
+
+export interface CoreApiResponseError {
+ // To distinguish the message from notifications
+ type: "error";
+ operation: string;
+ id: string;
+ error: TalerErrorDetail;
+}
+
+export interface WithdrawTestBalanceRequest {
+ amount: AmountString;
+ /**
+ * Corebank API base URL.
+ */
+ corebankApiBaseUrl: string;
+ exchangeBaseUrl: string;
+ forcedDenomSel?: ForcedDenomSel;
+}
+
+/**
+ * Request to the crypto worker to make a sync signature.
+ */
+export interface MakeSyncSignatureRequest {
+ accountPriv: string;
+ oldHash: string | undefined;
+ newHash: string;
+}
+
+/**
+ * Planchet for a coin during refresh.
+ */
+export interface RefreshPlanchetInfo {
+ /**
+ * Public key for the coin.
+ */
+ coinPub: string;
+
+ /**
+ * Private key for the coin.
+ */
+ coinPriv: string;
+
+ /**
+ * Blinded public key.
+ */
+ coinEv: CoinEnvelope;
+
+ coinEvHash: string;
+
+ /**
+ * Blinding key used.
+ */
+ blindingKey: string;
+
+ maxAge: number;
+ ageCommitmentProof?: AgeCommitmentProof;
+}
+
+/**
+ * Strategy for loading recovery information.
+ */
+export enum RecoveryMergeStrategy {
+ /**
+ * Keep the local wallet root key, import and take over providers.
+ */
+ Ours = "ours",
+
+ /**
+ * Migrate to the wallet root key from the recovery information.
+ */
+ Theirs = "theirs",
+}
+
+/**
+ * Load recovery information into the wallet.
+ */
+export interface RecoveryLoadRequest {
+ recovery: BackupRecovery;
+ strategy?: RecoveryMergeStrategy;
+}
+
+export const codecForWithdrawTestBalance =
+ (): Codec<WithdrawTestBalanceRequest> =>
+ buildCodecForObject<WithdrawTestBalanceRequest>()
+ .property("amount", codecForAmountString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("forcedDenomSel", codecForAny())
+ .property("corebankApiBaseUrl", codecForString())
+ .build("WithdrawTestBalanceRequest");
+
+export interface SetCoinSuspendedRequest {
+ coinPub: string;
+ suspended: boolean;
+}
+
+export const codecForSetCoinSuspendedRequest =
+ (): Codec<SetCoinSuspendedRequest> =>
+ buildCodecForObject<SetCoinSuspendedRequest>()
+ .property("coinPub", codecForString())
+ .property("suspended", codecForBoolean())
+ .build("SetCoinSuspendedRequest");
+
+export interface RefreshCoinSpec {
+ coinPub: string;
+ amount?: AmountString;
+}
+
+export const codecForRefreshCoinSpec = (): Codec<RefreshCoinSpec> =>
+ buildCodecForObject<RefreshCoinSpec>()
+ .property("amount", codecForAmountString())
+ .property("coinPub", codecForString())
+ .build("ForceRefreshRequest");
+
+export interface ForceRefreshRequest {
+ refreshCoinSpecs: RefreshCoinSpec[];
+}
+
+export const codecForForceRefreshRequest = (): Codec<ForceRefreshRequest> =>
+ buildCodecForObject<ForceRefreshRequest>()
+ .property("refreshCoinSpecs", codecForList(codecForRefreshCoinSpec()))
+ .build("ForceRefreshRequest");
+
+export interface PrepareRefundRequest {
+ talerRefundUri: string;
+}
+
+export interface StartRefundQueryForUriResponse {
+ /**
+ * Transaction id of the *payment* where the refund query was started.
+ */
+ transactionId: TransactionIdStr;
+}
+
+export const codecForPrepareRefundRequest = (): Codec<PrepareRefundRequest> =>
+ buildCodecForObject<PrepareRefundRequest>()
+ .property("talerRefundUri", codecForString())
+ .build("PrepareRefundRequest");
+
+export interface StartRefundQueryRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForStartRefundQueryRequest =
+ (): Codec<StartRefundQueryRequest> =>
+ buildCodecForObject<StartRefundQueryRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("StartRefundQueryRequest");
+
+export interface PrepareRewardRequest {
+ talerRewardUri: string;
+}
+
+export const codecForPrepareRewardRequest = (): Codec<PrepareRewardRequest> =>
+ buildCodecForObject<PrepareRewardRequest>()
+ .property("talerRewardUri", codecForString())
+ .build("PrepareRewardRequest");
+
+export interface AcceptRewardRequest {
+ /**
+ * @deprecated use transactionId
+ */
+ walletRewardId?: string;
+ /**
+ * it will be required when "walletRewardId" is removed
+ */
+ transactionId?: TransactionIdStr;
+}
+
+export const codecForAcceptTipRequest = (): Codec<AcceptRewardRequest> =>
+ buildCodecForObject<AcceptRewardRequest>()
+ .property("walletRewardId", codecOptional(codecForString()))
+ .property("transactionId", codecOptional(codecForTransactionIdStr()))
+ .build("AcceptRewardRequest");
+
+export interface FailTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForFailTransactionRequest =
+ (): Codec<FailTransactionRequest> =>
+ buildCodecForObject<FailTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("FailTransactionRequest");
+
+export interface SuspendTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForSuspendTransaction =
+ (): Codec<SuspendTransactionRequest> =>
+ buildCodecForObject<AbortTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("SuspendTransactionRequest");
+
+export interface ResumeTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForResumeTransaction = (): Codec<ResumeTransactionRequest> =>
+ buildCodecForObject<ResumeTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("ResumeTransactionRequest");
+
+export interface AbortTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export interface FailTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForAbortTransaction = (): Codec<AbortTransactionRequest> =>
+ buildCodecForObject<AbortTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("AbortTransactionRequest");
+
+export interface DepositGroupFees {
+ coin: AmountString;
+ wire: AmountString;
+ refresh: AmountString;
+}
+
+export interface CreateDepositGroupRequest {
+ /**
+ * Pre-allocated transaction ID.
+ * Allows clients to easily handle notifications
+ * that occur while the operation has been created but
+ * before the creation request has returned.
+ */
+ transactionId?: TransactionIdStr;
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+
+export interface PrepareDepositRequest {
+ depositPaytoUri: string;
+ amount: AmountString;
+}
+export const codecForPrepareDepositRequest = (): Codec<PrepareDepositRequest> =>
+ buildCodecForObject<PrepareDepositRequest>()
+ .property("amount", codecForAmountString())
+ .property("depositPaytoUri", codecForString())
+ .build("PrepareDepositRequest");
+
+export interface PrepareDepositResponse {
+ totalDepositCost: AmountString;
+ effectiveDepositAmount: AmountString;
+ fees: DepositGroupFees;
+}
+
+export const codecForCreateDepositGroupRequest =
+ (): Codec<CreateDepositGroupRequest> =>
+ buildCodecForObject<CreateDepositGroupRequest>()
+ .property("amount", codecForAmountString())
+ .property("depositPaytoUri", codecForString())
+ .property("transactionId", codecOptional(codecForTransactionIdStr()))
+ .build("CreateDepositGroupRequest");
+
+export interface CreateDepositGroupResponse {
+ depositGroupId: string;
+ transactionId: TransactionIdStr;
+}
+
+export interface TxIdResponse {
+ transactionId: TransactionIdStr;
+}
+
+export interface WithdrawUriInfoResponse {
+ operationId: string;
+ status: WithdrawalOperationStatus;
+ confirmTransferUrl?: string;
+ amount: AmountString;
+ defaultExchangeBaseUrl?: string;
+ possibleExchanges: ExchangeListItem[];
+}
+
+export const codecForWithdrawUriInfoResponse =
+ (): Codec<WithdrawUriInfoResponse> =>
+ buildCodecForObject<WithdrawUriInfoResponse>()
+ .property("operationId", codecForString())
+ .property("confirmTransferUrl", codecOptional(codecForString()))
+ .property(
+ "status",
+ codecForEither(
+ codecForConstString("pending"),
+ codecForConstString("selected"),
+ codecForConstString("aborted"),
+ codecForConstString("confirmed"),
+ ),
+ )
+ .property("amount", codecForAmountString())
+ .property("defaultExchangeBaseUrl", codecOptional(codecForString()))
+ .property("possibleExchanges", codecForList(codecForExchangeListItem()))
+ .build("WithdrawUriInfoResponse");
+
+export interface WalletCurrencyInfo {
+ trustedAuditors: {
+ currency: string;
+ auditorPub: string;
+ auditorBaseUrl: string;
+ }[];
+ trustedExchanges: {
+ currency: string;
+ exchangeMasterPub: string;
+ exchangeBaseUrl: string;
+ }[];
+}
+
+export interface TestingListTasksForTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export interface TestingListTasksForTransactionsResponse {
+ taskIdList: string[];
+}
+
+export const codecForTestingListTasksForTransactionRequest =
+ (): Codec<TestingListTasksForTransactionRequest> =>
+ buildCodecForObject<TestingListTasksForTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("TestingListTasksForTransactionRequest");
+
+export interface DeleteTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export interface RetryTransactionRequest {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForDeleteTransactionRequest =
+ (): Codec<DeleteTransactionRequest> =>
+ buildCodecForObject<DeleteTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("DeleteTransactionRequest");
+
+export const codecForRetryTransactionRequest =
+ (): Codec<RetryTransactionRequest> =>
+ buildCodecForObject<RetryTransactionRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("RetryTransactionRequest");
+
+export interface SetWalletDeviceIdRequest {
+ /**
+ * New wallet device ID to set.
+ */
+ walletDeviceId: string;
+}
+
+export const codecForSetWalletDeviceIdRequest =
+ (): Codec<SetWalletDeviceIdRequest> =>
+ buildCodecForObject<SetWalletDeviceIdRequest>()
+ .property("walletDeviceId", codecForString())
+ .build("SetWalletDeviceIdRequest");
+
+export interface WithdrawFakebankRequest {
+ amount: AmountString;
+ exchange: string;
+ bank: string;
+}
+
+export enum AttentionPriority {
+ High = "high",
+ Medium = "medium",
+ Low = "low",
+}
+
+export interface UserAttentionByIdRequest {
+ entityId: string;
+ type: AttentionType;
+}
+
+export const codecForUserAttentionByIdRequest =
+ (): Codec<UserAttentionByIdRequest> =>
+ buildCodecForObject<UserAttentionByIdRequest>()
+ .property("type", codecForAny())
+ .property("entityId", codecForString())
+ .build("UserAttentionByIdRequest");
+
+export const codecForUserAttentionsRequest = (): Codec<UserAttentionsRequest> =>
+ buildCodecForObject<UserAttentionsRequest>()
+ .property(
+ "priority",
+ codecOptional(
+ codecForEither(
+ codecForConstString(AttentionPriority.Low),
+ codecForConstString(AttentionPriority.Medium),
+ codecForConstString(AttentionPriority.High),
+ ),
+ ),
+ )
+ .build("UserAttentionsRequest");
+
+export interface UserAttentionsRequest {
+ priority?: AttentionPriority;
+}
+
+export type AttentionInfo =
+ | AttentionKycWithdrawal
+ | AttentionBackupUnpaid
+ | AttentionBackupExpiresSoon
+ | AttentionMerchantRefund
+ | AttentionExchangeTosChanged
+ | AttentionExchangeKeyExpired
+ | AttentionExchangeDenominationExpired
+ | AttentionAuditorTosChanged
+ | AttentionAuditorKeyExpires
+ | AttentionAuditorDenominationExpires
+ | AttentionPullPaymentPaid
+ | AttentionPushPaymentReceived;
+
+export enum AttentionType {
+ KycWithdrawal = "kyc-withdrawal",
+
+ BackupUnpaid = "backup-unpaid",
+ BackupExpiresSoon = "backup-expires-soon",
+ MerchantRefund = "merchant-refund",
+
+ ExchangeTosChanged = "exchange-tos-changed",
+ ExchangeKeyExpired = "exchange-key-expired",
+ ExchangeKeyExpiresSoon = "exchange-key-expires-soon",
+ ExchangeDenominationsExpired = "exchange-denominations-expired",
+ ExchangeDenominationsExpiresSoon = "exchange-denominations-expires-soon",
+
+ AuditorTosChanged = "auditor-tos-changed",
+ AuditorKeyExpires = "auditor-key-expires",
+ AuditorDenominationsExpires = "auditor-denominations-expires",
+
+ PullPaymentPaid = "pull-payment-paid",
+ PushPaymentReceived = "push-payment-withdrawn",
+}
+
+export const UserAttentionPriority: {
+ [type in AttentionType]: AttentionPriority;
+} = {
+ "kyc-withdrawal": AttentionPriority.Medium,
+
+ "backup-unpaid": AttentionPriority.High,
+ "backup-expires-soon": AttentionPriority.Medium,
+ "merchant-refund": AttentionPriority.Medium,
+
+ "exchange-tos-changed": AttentionPriority.Medium,
+
+ "exchange-key-expired": AttentionPriority.High,
+ "exchange-key-expires-soon": AttentionPriority.Medium,
+ "exchange-denominations-expired": AttentionPriority.High,
+ "exchange-denominations-expires-soon": AttentionPriority.Medium,
+
+ "auditor-tos-changed": AttentionPriority.Medium,
+ "auditor-key-expires": AttentionPriority.Medium,
+ "auditor-denominations-expires": AttentionPriority.Medium,
+
+ "pull-payment-paid": AttentionPriority.High,
+ "push-payment-withdrawn": AttentionPriority.High,
+};
+
+interface AttentionBackupExpiresSoon {
+ type: AttentionType.BackupExpiresSoon;
+ provider_base_url: string;
+}
+interface AttentionBackupUnpaid {
+ type: AttentionType.BackupUnpaid;
+ provider_base_url: string;
+ talerUri: string;
+}
+
+interface AttentionMerchantRefund {
+ type: AttentionType.MerchantRefund;
+ transactionId: TransactionIdStr;
+}
+
+interface AttentionKycWithdrawal {
+ type: AttentionType.KycWithdrawal;
+ transactionId: TransactionIdStr;
+}
+
+interface AttentionExchangeTosChanged {
+ type: AttentionType.ExchangeTosChanged;
+ exchange_base_url: string;
+}
+interface AttentionExchangeKeyExpired {
+ type: AttentionType.ExchangeKeyExpired;
+ exchange_base_url: string;
+}
+interface AttentionExchangeDenominationExpired {
+ type: AttentionType.ExchangeDenominationsExpired;
+ exchange_base_url: string;
+}
+interface AttentionAuditorTosChanged {
+ type: AttentionType.AuditorTosChanged;
+ auditor_base_url: string;
+}
+
+interface AttentionAuditorKeyExpires {
+ type: AttentionType.AuditorKeyExpires;
+ auditor_base_url: string;
+}
+interface AttentionAuditorDenominationExpires {
+ type: AttentionType.AuditorDenominationsExpires;
+ auditor_base_url: string;
+}
+interface AttentionPullPaymentPaid {
+ type: AttentionType.PullPaymentPaid;
+ transactionId: TransactionIdStr;
+}
+
+interface AttentionPushPaymentReceived {
+ type: AttentionType.PushPaymentReceived;
+ transactionId: TransactionIdStr;
+}
+
+export type UserAttentionUnreadList = Array<{
+ info: AttentionInfo;
+ when: TalerPreciseTimestamp;
+ read: boolean;
+}>;
+
+export interface UserAttentionsResponse {
+ pending: UserAttentionUnreadList;
+}
+
+export interface UserAttentionsCountResponse {
+ total: number;
+}
+
+export const codecForWithdrawFakebankRequest =
+ (): Codec<WithdrawFakebankRequest> =>
+ buildCodecForObject<WithdrawFakebankRequest>()
+ .property("amount", codecForAmountString())
+ .property("bank", codecForString())
+ .property("exchange", codecForString())
+ .build("WithdrawFakebankRequest");
+
+export interface ActiveTask {
+ taskId: string;
+ transaction: TransactionIdStr | undefined;
+ firstTry: AbsoluteTime | undefined;
+ nextTry: AbsoluteTime | undefined;
+ retryCounter: number | undefined;
+ lastError: TalerErrorDetail | undefined;
+}
+
+export interface GetActiveTasksResponse {
+ tasks: ActiveTask[];
+}
+
+export const codecForActiveTask = (): Codec<ActiveTask> =>
+ buildCodecForObject<ActiveTask>()
+ .property("taskId", codecForString())
+ .property("transaction", codecOptional(codecForTransactionIdStr()))
+ .property("retryCounter", codecOptional(codecForNumber()))
+ .property("firstTry", codecOptional(codecForAbsoluteTime))
+ .property("nextTry", codecOptional(codecForAbsoluteTime))
+ .property("lastError", codecOptional(codecForTalerErrorDetail()))
+ .build("ActiveTask");
+
+export const codecForGetActiveTasks = (): Codec<GetActiveTasksResponse> =>
+ buildCodecForObject<GetActiveTasksResponse>()
+ .property("tasks", codecForList(codecForActiveTask()))
+ .build("GetActiveTasks");
+
+export interface ImportDbRequest {
+ dump: any;
+}
+
+export const codecForImportDbRequest = (): Codec<ImportDbRequest> =>
+ buildCodecForObject<ImportDbRequest>()
+ .property("dump", codecForAny())
+ .build("ImportDbRequest");
+
+export interface ForcedDenomSel {
+ denoms: {
+ value: AmountString;
+ count: number;
+ }[];
+}
+
+/**
+ * Forced coin selection for deposits/payments.
+ */
+export interface ForcedCoinSel {
+ coins: {
+ value: AmountString;
+ contribution: AmountString;
+ }[];
+}
+
+export interface TestPayResult {
+ /**
+ * Number of coins used for the payment.
+ */
+ numCoins: number;
+}
+
+export interface SelectedCoin {
+ denomPubHash: string;
+ coinPub: string;
+ contribution: AmountString;
+ exchangeBaseUrl: string;
+}
+
+export interface SelectedProspectiveCoin {
+ denomPubHash: string;
+ contribution: AmountString;
+ exchangeBaseUrl: string;
+}
+
+/**
+ * Result of selecting coins, contains the exchange, and selected
+ * coins with their denomination.
+ */
+export interface PayCoinSelection {
+ coins: SelectedCoin[];
+
+ /**
+ * How much of the wire fees is the customer paying?
+ */
+ customerWireFees: AmountString;
+
+ /**
+ * How much of the deposit fees is the customer paying?
+ */
+ customerDepositFees: AmountString;
+}
+
+export interface ProspectivePayCoinSelection {
+ prospectiveCoins: SelectedProspectiveCoin[];
+
+ /**
+ * How much of the wire fees is the customer paying?
+ */
+ customerWireFees: AmountString;
+
+ /**
+ * How much of the deposit fees is the customer paying?
+ */
+ customerDepositFees: AmountString;
+}
+
+export interface CheckPeerPushDebitRequest {
+ /**
+ * Preferred exchange to use for the p2p payment.
+ */
+ exchangeBaseUrl?: string;
+
+ /**
+ * Instructed amount.
+ *
+ * FIXME: Allow specifying the instructed amount type.
+ */
+ amount: AmountString;
+}
+
+export const codecForCheckPeerPushDebitRequest =
+ (): Codec<CheckPeerPushDebitRequest> =>
+ buildCodecForObject<CheckPeerPushDebitRequest>()
+ .property("exchangeBaseUrl", codecOptional(codecForString()))
+ .property("amount", codecForAmountString())
+ .build("CheckPeerPushDebitRequest");
+
+export interface CheckPeerPushDebitResponse {
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+ exchangeBaseUrl: string;
+ /**
+ * Maximum expiration date, based on how close the coins
+ * used for the payment are to expiry.
+ *
+ * The value is based on when the wallet would typically
+ * automatically refresh the coins on its own, leaving enough
+ * time to get a refund for the push payment and refresh the
+ * coin.
+ */
+ maxExpirationDate: TalerProtocolTimestamp;
+}
+
+export interface InitiatePeerPushDebitRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+export interface InitiatePeerPushDebitResponse {
+ exchangeBaseUrl: string;
+ pursePub: string;
+ mergePriv: string;
+ contractPriv: string;
+ transactionId: TransactionIdStr;
+}
+
+export const codecForInitiatePeerPushDebitRequest =
+ (): Codec<InitiatePeerPushDebitRequest> =>
+ buildCodecForObject<InitiatePeerPushDebitRequest>()
+ .property("partialContractTerms", codecForPeerContractTerms())
+ .build("InitiatePeerPushDebitRequest");
+
+export interface PreparePeerPushCreditRequest {
+ talerUri: string;
+}
+
+export interface PreparePeerPullDebitRequest {
+ talerUri: string;
+}
+
+export interface PreparePeerPushCreditResponse {
+ contractTerms: PeerContractTerms;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+
+ transactionId: TransactionIdStr;
+
+ exchangeBaseUrl: string;
+
+ /**
+ * @deprecated use transaction ID instead.
+ */
+ peerPushCreditId: string;
+
+ /**
+ * @deprecated
+ */
+ amount: AmountString;
+}
+
+export interface PreparePeerPullDebitResponse {
+ contractTerms: PeerContractTerms;
+ /**
+ * @deprecated Redundant field with bad name, will be removed soon.
+ */
+ amount: AmountString;
+
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+
+ peerPullDebitId: string;
+
+ transactionId: TransactionIdStr;
+}
+
+export const codecForPreparePeerPushCreditRequest =
+ (): Codec<PreparePeerPushCreditRequest> =>
+ buildCodecForObject<PreparePeerPushCreditRequest>()
+ .property("talerUri", codecForString())
+ .build("CheckPeerPushPaymentRequest");
+
+export const codecForCheckPeerPullPaymentRequest =
+ (): Codec<PreparePeerPullDebitRequest> =>
+ buildCodecForObject<PreparePeerPullDebitRequest>()
+ .property("talerUri", codecForString())
+ .build("PreparePeerPullDebitRequest");
+
+export interface ConfirmPeerPushCreditRequest {
+ transactionId: string;
+}
+export interface AcceptPeerPushPaymentResponse {
+ transactionId: TransactionIdStr;
+}
+
+export interface AcceptPeerPullPaymentResponse {
+ transactionId: TransactionIdStr;
+}
+
+export const codecForConfirmPeerPushPaymentRequest =
+ (): Codec<ConfirmPeerPushCreditRequest> =>
+ buildCodecForObject<ConfirmPeerPushCreditRequest>()
+ .property("transactionId", codecForString())
+ .build("ConfirmPeerPushCreditRequest");
+
+export interface ConfirmPeerPullDebitRequest {
+ transactionId: TransactionIdStr;
+}
+
+export interface ApplyDevExperimentRequest {
+ devExperimentUri: string;
+}
+
+export const codecForApplyDevExperiment =
+ (): Codec<ApplyDevExperimentRequest> =>
+ buildCodecForObject<ApplyDevExperimentRequest>()
+ .property("devExperimentUri", codecForString())
+ .build("ApplyDevExperimentRequest");
+
+export const codecForAcceptPeerPullPaymentRequest =
+ (): Codec<ConfirmPeerPullDebitRequest> =>
+ buildCodecForObject<ConfirmPeerPullDebitRequest>()
+ .property("transactionId", codecForTransactionIdStr())
+ .build("ConfirmPeerPullDebitRequest");
+
+export interface CheckPeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ amount: AmountString;
+}
+export const codecForPreparePeerPullPaymentRequest =
+ (): Codec<CheckPeerPullCreditRequest> =>
+ buildCodecForObject<CheckPeerPullCreditRequest>()
+ .property("amount", codecForAmountString())
+ .property("exchangeBaseUrl", codecOptional(codecForString()))
+ .build("CheckPeerPullCreditRequest");
+
+export interface CheckPeerPullCreditResponse {
+ exchangeBaseUrl: string;
+ amountRaw: AmountString;
+ amountEffective: AmountString;
+
+ /**
+ * Number of coins that will be used,
+ * can be used by the UI to warn if excessively large.
+ */
+ numCoins: number;
+}
+export interface InitiatePeerPullCreditRequest {
+ exchangeBaseUrl?: string;
+ partialContractTerms: PeerContractTerms;
+}
+
+export const codecForInitiatePeerPullPaymentRequest =
+ (): Codec<InitiatePeerPullCreditRequest> =>
+ buildCodecForObject<InitiatePeerPullCreditRequest>()
+ .property("partialContractTerms", codecForPeerContractTerms())
+ .property("exchangeBaseUrl", codecOptional(codecForString()))
+ .build("InitiatePeerPullCreditRequest");
+
+export interface InitiatePeerPullCreditResponse {
+ /**
+ * Taler URI for the other party to make the payment
+ * that was requested.
+ *
+ * @deprecated since it's not necessarily valid yet until the tx is in the right state
+ */
+ talerUri: string;
+
+ transactionId: TransactionIdStr;
+}
+
+export interface ValidateIbanRequest {
+ iban: string;
+}
+
+export const codecForValidateIbanRequest = (): Codec<ValidateIbanRequest> =>
+ buildCodecForObject<ValidateIbanRequest>()
+ .property("iban", codecForString())
+ .build("ValidateIbanRequest");
+
+export interface ValidateIbanResponse {
+ valid: boolean;
+}
+
+export const codecForValidateIbanResponse = (): Codec<ValidateIbanResponse> =>
+ buildCodecForObject<ValidateIbanResponse>()
+ .property("valid", codecForBoolean())
+ .build("ValidateIbanResponse");
+
+export type TransactionStateFilter = "nonfinal";
+
+export interface TransactionRecordFilter {
+ onlyState?: TransactionStateFilter;
+ onlyCurrency?: string;
+}
+
+export interface StoredBackupList {
+ storedBackups: {
+ name: string;
+ }[];
+}
+
+export interface CreateStoredBackupResponse {
+ name: string;
+}
+
+export interface RecoverStoredBackupRequest {
+ name: string;
+}
+
+export interface DeleteStoredBackupRequest {
+ name: string;
+}
+
+export const codecForDeleteStoredBackupRequest =
+ (): Codec<DeleteStoredBackupRequest> =>
+ buildCodecForObject<DeleteStoredBackupRequest>()
+ .property("name", codecForString())
+ .build("DeleteStoredBackupRequest");
+
+export const codecForRecoverStoredBackupRequest =
+ (): Codec<RecoverStoredBackupRequest> =>
+ buildCodecForObject<RecoverStoredBackupRequest>()
+ .property("name", codecForString())
+ .build("RecoverStoredBackupRequest");
+
+export interface TestingSetTimetravelRequest {
+ offsetMs: number;
+}
+
+export const codecForTestingSetTimetravelRequest =
+ (): Codec<TestingSetTimetravelRequest> =>
+ buildCodecForObject<TestingSetTimetravelRequest>()
+ .property("offsetMs", codecForNumber())
+ .build("TestingSetTimetravelRequest");
+
+export interface AllowedAuditorInfo {
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export interface AllowedExchangeInfo {
+ exchangeBaseUrl: string;
+ exchangePub: string;
+}
+
+/**
+ * Data extracted from the contract terms that is relevant for payment
+ * processing in the wallet.
+ */
+export interface WalletContractData {
+ /**
+ * Fulfillment URL, or the empty string if the order has no fulfillment URL.
+ *
+ * Stored as a non-nullable string as we use this field for IndexedDB indexing.
+ */
+ fulfillmentUrl: string;
+
+ contractTermsHash: string;
+ fulfillmentMessage?: string;
+ fulfillmentMessageI18n?: InternationalizedString;
+ merchantSig: string;
+ merchantPub: string;
+ merchant: MerchantInfo;
+ amount: AmountString;
+ orderId: string;
+ merchantBaseUrl: string;
+ summary: string;
+ summaryI18n: { [lang_tag: string]: string } | undefined;
+ autoRefund: TalerProtocolDuration | undefined;
+ payDeadline: TalerProtocolTimestamp;
+ refundDeadline: TalerProtocolTimestamp;
+ allowedExchanges: AllowedExchangeInfo[];
+ timestamp: TalerProtocolTimestamp;
+ wireMethod: string;
+ wireInfoHash: string;
+ maxDepositFee: AmountString;
+ minimumAge?: number;
+}
+
+export interface TestingWaitTransactionRequest {
+ transactionId: TransactionIdStr;
+ txState: TransactionState;
+}
+
+export interface TestingGetDenomStatsRequest {
+ exchangeBaseUrl: string;
+}
+
+export interface TestingGetDenomStatsResponse {
+ numKnown: number;
+ numOffered: number;
+ numLost: number;
+}
+
+export const codecForTestingGetDenomStatsRequest =
+ (): Codec<TestingGetDenomStatsRequest> =>
+ buildCodecForObject<TestingGetDenomStatsRequest>()
+ .property("exchangeBaseUrl", codecForString())
+ .build("TestingGetDenomStatsRequest");
+
+export interface WithdrawalExchangeAccountDetails {
+ /**
+ * Payto URI to credit the exchange.
+ *
+ * Depending on whether the (manual!) withdrawal is accepted or just
+ * being checked, this already includes the subject with the
+ * reserve public key.
+ */
+ paytoUri: string;
+
+ /**
+ * Status that indicates whether the account can be used
+ * by the user to send funds for a withdrawal.
+ *
+ * ok: account should be shown to the user
+ * error: account should not be shown to the user, UIs might render the error (in conversionError),
+ * especially in dev mode.
+ */
+ status: "ok" | "error";
+
+ /**
+ * Transfer amount. Might be in a different currency than the requested
+ * amount for withdrawal.
+ *
+ * Absent if this is a conversion account and the conversion failed.
+ */
+ transferAmount?: AmountString;
+
+ /**
+ * Currency specification for the external currency.
+ *
+ * Only included if this account requires a currency conversion.
+ */
+ currencySpecification?: CurrencySpecification;
+
+ /**
+ * Further restrictions for sending money to the
+ * exchange.
+ */
+ creditRestrictions?: AccountRestriction[];
+
+ /**
+ * Label given to the account or the account's bank by the exchange.
+ */
+ bankLabel?: string;
+
+ /*
+ * Display priority assigned to this bank account by the exchange.
+ */
+ priority?: number;
+
+ /**
+ * Error that happened when attempting to request the conversion rate.
+ */
+ conversionError?: TalerErrorDetail;
+}
+
+export interface PrepareWithdrawExchangeRequest {
+ /**
+ * A taler://withdraw-exchange URI.
+ */
+ talerUri: string;
+}
+
+export const codecForPrepareWithdrawExchangeRequest =
+ (): Codec<PrepareWithdrawExchangeRequest> =>
+ buildCodecForObject<PrepareWithdrawExchangeRequest>()
+ .property("talerUri", codecForString())
+ .build("PrepareWithdrawExchangeRequest");
+
+export interface PrepareWithdrawExchangeResponse {
+ /**
+ * Base URL of the exchange that already existed
+ * or was ephemerally added as an exchange entry to
+ * the wallet.
+ */
+ exchangeBaseUrl: string;
+
+ /**
+ * Amount from the taler://withdraw-exchange URI.
+ * Only present if specified in the URI.
+ */
+ amount?: AmountString;
+}
+
+export interface ExchangeEntryState {
+ tosStatus: ExchangeTosStatus;
+ exchangeEntryStatus: ExchangeEntryStatus;
+ exchangeUpdateStatus: ExchangeUpdateStatus;
+}
+
+export interface ListGlobalCurrencyAuditorsResponse {
+ auditors: {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+ }[];
+}
+
+export interface ListGlobalCurrencyExchangesResponse {
+ exchanges: {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+ }[];
+}
+
+export interface AddGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+export const codecForAddGlobalCurrencyExchangeRequest =
+ (): Codec<AddGlobalCurrencyExchangeRequest> =>
+ buildCodecForObject<AddGlobalCurrencyExchangeRequest>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("exchangeMasterPub", codecForString())
+ .build("AddGlobalCurrencyExchangeRequest");
+
+export interface RemoveGlobalCurrencyExchangeRequest {
+ currency: string;
+ exchangeBaseUrl: string;
+ exchangeMasterPub: string;
+}
+
+export const codecForRemoveGlobalCurrencyExchangeRequest =
+ (): Codec<RemoveGlobalCurrencyExchangeRequest> =>
+ buildCodecForObject<RemoveGlobalCurrencyExchangeRequest>()
+ .property("currency", codecForString())
+ .property("exchangeBaseUrl", codecForString())
+ .property("exchangeMasterPub", codecForString())
+ .build("RemoveGlobalCurrencyExchangeRequest");
+
+export interface AddGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export const codecForAddGlobalCurrencyAuditorRequest =
+ (): Codec<AddGlobalCurrencyAuditorRequest> =>
+ buildCodecForObject<AddGlobalCurrencyAuditorRequest>()
+ .property("currency", codecForString())
+ .property("auditorBaseUrl", codecForString())
+ .property("auditorPub", codecForString())
+ .build("AddGlobalCurrencyAuditorRequest");
+
+export interface RemoveGlobalCurrencyAuditorRequest {
+ currency: string;
+ auditorBaseUrl: string;
+ auditorPub: string;
+}
+
+export const codecForRemoveGlobalCurrencyAuditorRequest =
+ (): Codec<RemoveGlobalCurrencyAuditorRequest> =>
+ buildCodecForObject<RemoveGlobalCurrencyAuditorRequest>()
+ .property("currency", codecForString())
+ .property("auditorBaseUrl", codecForString())
+ .property("auditorPub", codecForString())
+ .build("RemoveGlobalCurrencyAuditorRequest");
+
+/**
+ * Information about one provider.
+ *
+ * We don't store the account key here,
+ * as that's derived from the wallet root key.
+ */
+export interface ProviderInfo {
+ active: boolean;
+ syncProviderBaseUrl: string;
+ name: string;
+ terms?: BackupProviderTerms;
+ /**
+ * Last communication issue with the provider.
+ */
+ lastError?: TalerErrorDetail;
+ lastSuccessfulBackupTimestamp?: TalerPreciseTimestamp;
+ lastAttemptedBackupTimestamp?: TalerPreciseTimestamp;
+ paymentProposalIds: string[];
+ backupProblem?: BackupProblem;
+ paymentStatus: ProviderPaymentStatus;
+}
+
+export interface BackupProviderTerms {
+ supportedProtocolVersion: string;
+ annualFee: AmountString;
+ storageLimitInMegabytes: number;
+}
+
+export type BackupProblem =
+ | BackupUnreadableProblem
+ | BackupConflictingDeviceProblem;
+
+export interface BackupUnreadableProblem {
+ type: "backup-unreadable";
+}
+
+export interface BackupConflictingDeviceProblem {
+ type: "backup-conflicting-device";
+ otherDeviceId: string;
+ myDeviceId: string;
+ backupTimestamp: AbsoluteTime;
+}
+
+export type ProviderPaymentStatus =
+ | ProviderPaymentTermsChanged
+ | ProviderPaymentPaid
+ | ProviderPaymentInsufficientBalance
+ | ProviderPaymentUnpaid
+ | ProviderPaymentPending;
+
+export enum ProviderPaymentType {
+ Unpaid = "unpaid",
+ Pending = "pending",
+ InsufficientBalance = "insufficient-balance",
+ Paid = "paid",
+ TermsChanged = "terms-changed",
+}
+
+export interface ProviderPaymentUnpaid {
+ type: ProviderPaymentType.Unpaid;
+}
+
+export interface ProviderPaymentInsufficientBalance {
+ type: ProviderPaymentType.InsufficientBalance;
+ amount: AmountString;
+}
+
+export interface ProviderPaymentPending {
+ type: ProviderPaymentType.Pending;
+ talerUri?: string;
+}
+
+export interface ProviderPaymentPaid {
+ type: ProviderPaymentType.Paid;
+ paidUntil: AbsoluteTime;
+}
+
+export interface ProviderPaymentTermsChanged {
+ type: ProviderPaymentType.TermsChanged;
+ paidUntil: AbsoluteTime;
+ oldTerms: BackupProviderTerms;
+ newTerms: BackupProviderTerms;
+}
+
+// FIXME: Does not really belong here, move to sync API
+export interface SyncTermsOfServiceResponse {
+ // maximum backup size supported
+ storage_limit_in_megabytes: number;
+
+ // Fee for an account, per year.
+ annual_fee: AmountString;
+
+ // protocol version supported by the server,
+ // for now always "0.0".
+ version: string;
+}
+
+// FIXME: Does not really belong here, move to sync API
+export const codecForSyncTermsOfServiceResponse =
+ (): Codec<SyncTermsOfServiceResponse> =>
+ buildCodecForObject<SyncTermsOfServiceResponse>()
+ .property("storage_limit_in_megabytes", codecForNumber())
+ .property("annual_fee", codecForAmountString())
+ .property("version", codecForString())
+ .build("SyncTermsOfServiceResponse");