/* 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 */ /** * 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 */ /** * 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, canonicalizeBaseUrl, } 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 { 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 { 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 { 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}`, ); }, }; } export function codecForCanonBaseUrl(): Codec { return { decode(x: any, c?: Context): string { if (typeof x === "string") { const canon = canonicalizeBaseUrl(x); if (x !== canon) { throw new DecodingError( `expected canonicalized base URL at ${renderContext( c, )} but got value '${x}'`, ); } return x; } throw new DecodingError( `expected base URL at ${renderContext(c)} but got type ${typeof 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 => buildCodecForObject() .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() .property("amount", codecForAmountString()) .property( "type", codecForEither( codecForConstString(TransactionAmountMode.Raw), codecForConstString(TransactionAmountMode.Effective), ), ) .build("ConvertAmountRequest"); export interface GetAmountRequest { currency: string; } export const codecForGetAmountRequest = buildCodecForObject() .property("currency", codecForString()) .build("GetAmountRequest"); interface GetPlanToCompleteOperation { instructedAmount: AmountString; } const codecForGetPlanForWalletInitiatedOperation = < T extends GetPlanForWalletInitiatedOperation, >() => buildCodecForObject() .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() .property("type", codecForConstString(TransactionType.Withdrawal)) .property("exchangeUrl", codecOptional(codecForString())) .build("GetPlanForWithdrawRequest"); const codecForGetPlanForDepositRequest = codecForGetPlanForWalletInitiatedOperation() .property("type", codecForConstString(TransactionType.Deposit)) .property("account", codecForString()) .build("GetPlanForDepositRequest"); const codecForGetPlanForPushDebitRequest = codecForGetPlanForWalletInitiatedOperation() .property("type", codecForConstString(TransactionType.PeerPushDebit)) .build("GetPlanForPushDebitRequest"); const codecForGetPlanForPullCreditRequest = codecForGetPlanForWalletInitiatedOperation() .property("type", codecForConstString(TransactionType.PeerPullCredit)) .property("exchangeUrl", codecForString()) .build("GetPlanForPullCreditRequest"); interface GetPlanForPaymentRequest extends GetPlanToCompleteOperation { type: TransactionType.Payment; wireMethod: string; ageRestriction: number; maxDepositFee: AmountString; } interface GetPlanForPullDebitRequest extends GetPlanToCompleteOperation { type: TransactionType.PeerPullDebit; } interface GetPlanForPushCreditRequest extends GetPlanToCompleteOperation { type: TransactionType.PeerPushCredit; } const codecForGetPlanForPaymentRequest = buildCodecForObject() .property("type", codecForConstString(TransactionType.Payment)) .property("maxDepositFee", codecForAmountString()) .build("GetPlanForPaymentRequest"); const codecForGetPlanForPullDebitRequest = buildCodecForObject() .property("type", codecForConstString(TransactionType.PeerPullDebit)) .build("GetPlanForPullDebitRequest"); const codecForGetPlanForPushCreditRequest = buildCodecForObject() .property("type", codecForConstString(TransactionType.PeerPushCredit)) .build("GetPlanForPushCreditRequest"); export const codecForGetPlanForOperationRequest = (): Codec => buildCodecForUnion() .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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .property("currency", codecForString()) .property("type", codecForConstString(ScopeType.Global)) .build("ScopeInfoGlobal"); export const codecForScopeInfoExchange = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("type", codecForConstString(ScopeType.Exchange)) .property("url", codecForString()) .build("ScopeInfoExchange"); export const codecForScopeInfoAuditor = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("type", codecForConstString(ScopeType.Auditor)) .property("url", codecForString()) .build("ScopeInfoAuditor"); export const codecForScopeInfo = (): Codec => buildCodecForUnion() .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 => buildCodecForObject() .property("scope", codecForScopeInfo()) .build("GetCurrencySpecificationRequest"); export interface ListExchangesForScopedCurrencyRequest { scope: ScopeInfo; } export const codecForListExchangesForScopedCurrencyRequest = (): Codec => buildCodecForObject() .property("scope", codecForScopeInfo()) .build("ListExchangesForScopedCurrencyRequest"); export interface GetCurrencySpecificationResponse { currencySpecification: CurrencySpecification; } export interface BuiltinExchange { exchangeBaseUrl: string; currencyHint: string; } export interface PartialWalletRunConfig { builtin?: Partial; testing?: Partial; features?: Partial; } 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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .property("code", codecForNumber()) .property("when", codecOptional(codecForAbsoluteTime)) .property("hint", codecOptional(codecForString())) .build("TalerErrorDetail"); export type ConfirmPayResult = ConfirmPayResultDone | ConfirmPayResultPending; export const codecForConfirmPayResultPending = (): Codec => buildCodecForObject() .property("lastError", codecOptional(codecForTalerErrorDetail())) .property("transactionId", codecForTransactionIdStr()) .property("type", codecForConstString(ConfirmPayResultType.Pending)) .build("ConfirmPayResultPending"); export const codecForConfirmPayResultDone = (): Codec => buildCodecForObject() .property("type", codecForConstString(ConfirmPayResultType.Done)) .property("transactionId", codecForTransactionIdStr()) .property("contractTerms", codecForMerchantContractTerms()) .build("ConfirmPayResultDone"); export const codecForConfirmPayResult = (): Codec => buildCodecForUnion() .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 => buildCodecForObject() .property("reservePub", codecForString()) .build("ConfirmReserveRequest"); export interface PrepareRefundResult { proposalId: string; effectivePaid: AmountString; gone: AmountString; granted: AmountString; pending: boolean; awaiting: AmountString; info: OrderShortInfo; } 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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForUnion() .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; 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/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 => buildCodecForObject() .property("sig", codecForString()) .property("wireFee", codecForAmountString()) .property("closingFee", codecForAmountString()) .property("startStamp", codecForTimestamp) .property("endStamp", codecForTimestamp) .build("codecForWireFee"); const codecForWireInfo = (): Codec => buildCodecForObject() .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 = { [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 { 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; transferFees: Record; 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 => buildCodecForObject() .property("denom_pub_h", codecForString()) .property("auditor_sig", codecForString()) .build("AuditorDenomSig"); const codecForExchangeAuditor = (): Codec => buildCodecForObject() .property("auditor_pub", codecForString()) .property("auditor_url", codecForString()) .property("denomination_keys", codecForList(codecForAuditorDenomSig())) .build("codecForExchangeAuditor"); export const codecForFeeDescriptionPair = (): Codec => buildCodecForObject() .property("group", codecForString()) .property("from", codecForAbsoluteTime) .property("until", codecForAbsoluteTime) .property("left", codecOptional(codecForAmountString())) .property("right", codecOptional(codecForAmountString())) .build("FeeDescriptionPair"); export const codecForFeeDescription = (): Codec => buildCodecForObject() .property("group", codecForString()) .property("from", codecForAbsoluteTime) .property("until", codecForAbsoluteTime) .property("fee", codecOptional(codecForAmountString())) .build("FeeDescription"); export const codecForFeesByOperations = (): Codec< DenomOperationMap > => buildCodecForObject>() .property("deposit", codecForList(codecForFeeDescription())) .property("withdraw", codecForList(codecForFeeDescription())) .property("refresh", codecForList(codecForFeeDescription())) .property("refund", codecForList(codecForFeeDescription())) .build("DenomOperationMap"); export const codecForExchangeFullDetails = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("currency", codecForString()) .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .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 => buildCodecForObject() .property("merchantBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("merchantBaseUrl", codecForCanonBaseUrl()) .property("merchantAuthToken", codecOptional(codecForString())) .property("amountToSpend", codecForAmountString()) .property("amountToWithdraw", codecForAmountString()) .property("corebankApiBaseUrl", codecForCanonBaseUrl()) .build("IntegrationTestArgs"); export interface IntegrationTestV2Args { exchangeBaseUrl: string; corebankApiBaseUrl: string; merchantBaseUrl: string; merchantAuthToken?: string; } export const codecForIntegrationTestV2Args = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("merchantBaseUrl", codecForCanonBaseUrl()) .property("merchantAuthToken", codecOptional(codecForString())) .property("corebankApiBaseUrl", codecForCanonBaseUrl()) .build("IntegrationTestV2Args"); export interface GetExchangeEntryByUrlRequest { exchangeBaseUrl: string; } export const codecForGetExchangeEntryByUrlRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("forceUpdate", codecOptional(codecForBoolean())) .property("masterPub", codecOptional(codecForString())) .build("AddExchangeRequest"); export interface UpdateExchangeEntryRequest { exchangeBaseUrl: string; force?: boolean; } export const codecForUpdateExchangeEntryRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("force", codecOptional(codecForBoolean())) .build("UpdateExchangeEntryRequest"); export interface GetExchangeResourcesRequest { exchangeBaseUrl: string; } export const codecForGetExchangeResourcesRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .build("GetExchangeResourcesRequest"); export interface GetExchangeResourcesResponse { hasResources: boolean; } export interface DeleteExchangeRequest { exchangeBaseUrl: string; purge?: boolean; } export const codecForDeleteExchangeRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("purge", codecOptional(codecForBoolean())) .build("DeleteExchangeRequest"); export interface ForceExchangeUpdateRequest { exchangeBaseUrl: string; } export const codecForForceExchangeUpdateRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .build("AddExchangeRequest"); export interface GetExchangeTosRequest { exchangeBaseUrl: string; acceptedFormat?: string[]; acceptLanguage?: string; } export const codecForGetExchangeTosRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("transactionId", codecForString()) .build("ConfirmWithdrawalRequest"); export interface AcceptBankIntegratedWithdrawalRequest { talerWithdrawUri: string; exchangeBaseUrl: string; forcedDenomSel?: ForcedDenomSel; restrictAge?: number; } export const codecForAcceptBankIntegratedWithdrawalRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("talerWithdrawUri", codecForString()) .property("forcedDenomSel", codecForAny()) .property("restrictAge", codecOptional(codecForNumber())) .build("AcceptBankIntegratedWithdrawalRequest"); export const codecForGetWithdrawalDetailsForAmountRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("amount", codecForAmountString()) .property("restrictAge", codecOptional(codecForNumber())) .property("clientCancellationId", codecOptional(codecForString())) .build("GetWithdrawalDetailsForAmountRequest"); export interface AcceptExchangeTosRequest { exchangeBaseUrl: string; } export const codecForAcceptExchangeTosRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .build("AcceptExchangeTosRequest"); export interface ForgetExchangeTosRequest { exchangeBaseUrl: string; } export const codecForForgetExchangeTosRequest = (): Codec => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .build("ForgetExchangeTosRequest"); export interface AcceptRefundRequest { transactionId: TransactionIdStr; } export const codecForApplyRefundRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("AcceptRefundRequest"); export interface ApplyRefundFromPurchaseIdRequest { purchaseId: string; } export const codecForApplyRefundFromPurchaseIdRequest = (): Codec => buildCodecForObject() .property("purchaseId", codecForString()) .build("ApplyRefundFromPurchaseIdRequest"); export interface GetWithdrawalDetailsForUriRequest { talerWithdrawUri: string; restrictAge?: number; } export const codecForGetWithdrawalDetailsForUri = (): Codec => buildCodecForObject() .property("talerWithdrawUri", codecForString()) .property("restrictAge", codecOptional(codecForNumber())) .build("GetWithdrawalDetailsForUriRequest"); export interface ListKnownBankAccountsRequest { currency?: string; } export const codecForListKnownBankAccounts = (): Codec => buildCodecForObject() .property("currency", codecOptional(codecForString())) .build("ListKnownBankAccountsRequest"); export interface AddKnownBankAccountsRequest { payto: string; alias: string; currency: string; } export const codecForAddKnownBankAccounts = (): Codec => buildCodecForObject() .property("payto", codecForString()) .property("alias", codecForString()) .property("currency", codecForString()) .build("AddKnownBankAccountsRequest"); export interface ForgetKnownBankAccountsRequest { payto: string; } export const codecForForgetKnownBankAccounts = (): Codec => buildCodecForObject() .property("payto", codecForString()) .build("ForgetKnownBankAccountsRequest"); export interface AbortProposalRequest { proposalId: string; } export const codecForAbortProposalRequest = (): Codec => buildCodecForObject() .property("proposalId", codecForString()) .build("AbortProposalRequest"); export interface GetContractTermsDetailsRequest { // @deprecated use transaction id proposalId?: string; transactionId?: string; } export const codecForGetContractTermsDetails = (): Codec => buildCodecForObject() .property("proposalId", codecOptional(codecForString())) .property("transactionId", codecOptional(codecForString())) .build("GetContractTermsDetails"); export interface PreparePayRequest { talerPayUri: string; } export const codecForPreparePayRequest = (): Codec => buildCodecForObject() .property("talerPayUri", codecForString()) .build("PreparePay"); export interface SharePaymentRequest { merchantBaseUrl: string; orderId: string; } export const codecForSharePaymentRequest = (): Codec => buildCodecForObject() .property("merchantBaseUrl", codecForCanonBaseUrl()) .property("orderId", codecForString()) .build("SharePaymentRequest"); export interface SharePaymentResult { privatePayUri: string; } export const codecForSharePaymentResult = (): Codec => buildCodecForObject() .property("privatePayUri", codecForString()) .build("SharePaymentResult"); export interface PreparePayTemplateRequest { talerPayTemplateUri: string; templateParams?: TemplateParams; } export const codecForPreparePayTemplateRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .property("amount", codecForAmountString()) .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("forcedDenomSel", codecForAny()) .property("corebankApiBaseUrl", codecForCanonBaseUrl()) .build("WithdrawTestBalanceRequest"); export interface SetCoinSuspendedRequest { coinPub: string; suspended: boolean; } export const codecForSetCoinSuspendedRequest = (): Codec => buildCodecForObject() .property("coinPub", codecForString()) .property("suspended", codecForBoolean()) .build("SetCoinSuspendedRequest"); export interface RefreshCoinSpec { coinPub: string; amount?: AmountString; } export const codecForRefreshCoinSpec = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("coinPub", codecForString()) .build("ForceRefreshRequest"); export interface ForceRefreshRequest { refreshCoinSpecs: RefreshCoinSpec[]; } export const codecForForceRefreshRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("talerRefundUri", codecForString()) .build("PrepareRefundRequest"); export interface StartRefundQueryRequest { transactionId: TransactionIdStr; } export const codecForStartRefundQueryRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("StartRefundQueryRequest"); export interface FailTransactionRequest { transactionId: TransactionIdStr; } export const codecForFailTransactionRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("FailTransactionRequest"); export interface SuspendTransactionRequest { transactionId: TransactionIdStr; } export const codecForSuspendTransaction = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("SuspendTransactionRequest"); export interface ResumeTransactionRequest { transactionId: TransactionIdStr; } export const codecForResumeTransaction = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("ResumeTransactionRequest"); export interface AbortTransactionRequest { transactionId: TransactionIdStr; } export interface FailTransactionRequest { transactionId: TransactionIdStr; } export const codecForAbortTransaction = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("amount", codecForAmountString()) .property("depositPaytoUri", codecForString()) .build("PrepareDepositRequest"); export interface PrepareDepositResponse { totalDepositCost: AmountString; effectiveDepositAmount: AmountString; fees: DepositGroupFees; } export const codecForCreateDepositGroupRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("operationId", codecForString()) .property("confirmTransferUrl", codecOptional(codecForString())) .property( "status", codecForEither( codecForConstString("pending"), codecForConstString("selected"), codecForConstString("aborted"), codecForConstString("confirmed"), ), ) .property("amount", codecForAmountString()) .property("defaultExchangeBaseUrl", codecOptional(codecForCanonBaseUrl())) .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 => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("TestingListTasksForTransactionRequest"); export interface DeleteTransactionRequest { transactionId: TransactionIdStr; } export interface RetryTransactionRequest { transactionId: TransactionIdStr; } export const codecForDeleteTransactionRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("DeleteTransactionRequest"); export const codecForRetryTransactionRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("RetryTransactionRequest"); export interface SetWalletDeviceIdRequest { /** * New wallet device ID to set. */ walletDeviceId: string; } export const codecForSetWalletDeviceIdRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("type", codecForAny()) .property("entityId", codecForString()) .build("UserAttentionByIdRequest"); export const codecForUserAttentionsRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .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 => buildCodecForObject() .property("tasks", codecForList(codecForActiveTask())) .build("GetActiveTasks"); export interface ImportDbRequest { dump: any; } export const codecForImportDbRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("exchangeBaseUrl", codecOptional(codecForCanonBaseUrl())) .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 => buildCodecForObject() .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 => buildCodecForObject() .property("talerUri", codecForString()) .build("CheckPeerPushPaymentRequest"); export const codecForCheckPeerPullPaymentRequest = (): Codec => buildCodecForObject() .property("talerUri", codecForString()) .build("PreparePeerPullDebitRequest"); export interface ConfirmPeerPushCreditRequest { transactionId: string; } export interface AcceptPeerPushPaymentResponse { transactionId: TransactionIdStr; } export interface AcceptPeerPullPaymentResponse { transactionId: TransactionIdStr; } export const codecForConfirmPeerPushPaymentRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForString()) .build("ConfirmPeerPushCreditRequest"); export interface ConfirmPeerPullDebitRequest { transactionId: TransactionIdStr; } export interface ApplyDevExperimentRequest { devExperimentUri: string; } export const codecForApplyDevExperiment = (): Codec => buildCodecForObject() .property("devExperimentUri", codecForString()) .build("ApplyDevExperimentRequest"); export const codecForAcceptPeerPullPaymentRequest = (): Codec => buildCodecForObject() .property("transactionId", codecForTransactionIdStr()) .build("ConfirmPeerPullDebitRequest"); export interface CheckPeerPullCreditRequest { exchangeBaseUrl?: string; amount: AmountString; } export const codecForPreparePeerPullPaymentRequest = (): Codec => buildCodecForObject() .property("amount", codecForAmountString()) .property("exchangeBaseUrl", codecOptional(codecForCanonBaseUrl())) .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 => buildCodecForObject() .property("partialContractTerms", codecForPeerContractTerms()) .property("exchangeBaseUrl", codecOptional(codecForCanonBaseUrl())) .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 CanonicalizeBaseUrlRequest { url: string; } export const codecForCanonicalizeBaseUrlRequest = (): Codec => buildCodecForObject() .property("url", codecForString()) .build("CanonicalizeBaseUrlRequest"); export interface CanonicalizeBaseUrlResponse { url: string; } export interface ValidateIbanRequest { iban: string; } export const codecForValidateIbanRequest = (): Codec => buildCodecForObject() .property("iban", codecForString()) .build("ValidateIbanRequest"); export interface ValidateIbanResponse { valid: boolean; } export const codecForValidateIbanResponse = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("name", codecForString()) .build("DeleteStoredBackupRequest"); export const codecForRecoverStoredBackupRequest = (): Codec => buildCodecForObject() .property("name", codecForString()) .build("RecoverStoredBackupRequest"); export interface TestingSetTimetravelRequest { offsetMs: number; } export const codecForTestingSetTimetravelRequest = (): Codec => buildCodecForObject() .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 => buildCodecForObject() .property("exchangeBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .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 => buildCodecForObject() .property("currency", codecForString()) .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("exchangeMasterPub", codecForString()) .build("AddGlobalCurrencyExchangeRequest"); export interface RemoveGlobalCurrencyExchangeRequest { currency: string; exchangeBaseUrl: string; exchangeMasterPub: string; } export const codecForRemoveGlobalCurrencyExchangeRequest = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("exchangeBaseUrl", codecForCanonBaseUrl()) .property("exchangeMasterPub", codecForString()) .build("RemoveGlobalCurrencyExchangeRequest"); export interface AddGlobalCurrencyAuditorRequest { currency: string; auditorBaseUrl: string; auditorPub: string; } export const codecForAddGlobalCurrencyAuditorRequest = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("auditorBaseUrl", codecForCanonBaseUrl()) .property("auditorPub", codecForString()) .build("AddGlobalCurrencyAuditorRequest"); export interface RemoveGlobalCurrencyAuditorRequest { currency: string; auditorBaseUrl: string; auditorPub: string; } export const codecForRemoveGlobalCurrencyAuditorRequest = (): Codec => buildCodecForObject() .property("currency", codecForString()) .property("auditorBaseUrl", codecForCanonBaseUrl()) .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 => buildCodecForObject() .property("storage_limit_in_megabytes", codecForNumber()) .property("annual_fee", codecForAmountString()) .property("version", codecForString()) .build("SyncTermsOfServiceResponse");