taler-typescript-core

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

commit 861c27f9c866717e4c764fb9e9ddeb2fb0d97459
parent ccad582b4380ac4344cb231b95072743e3d20909
Author: Florian Dold <florian@dold.me>
Date:   Mon, 27 Jan 2025 12:06:45 +0100

fix duplicate message definition

Diffstat:
Mpackages/taler-util/src/http-client/exchange.ts | 4++--
Mpackages/taler-util/src/types-taler-exchange.ts | 252+++++++++++++------------------------------------------------------------------
Mpackages/taler-wallet-core/src/exchanges.ts | 44++++++++++++++++++++++----------------------
3 files changed, 64 insertions(+), 236 deletions(-)

diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts @@ -70,7 +70,7 @@ import { codecForAvailableMeasureSummary, codecForEventCounter, codecForExchangeConfig, - codecForExchangeKeys, + codecForExchangeKeysResponse, codecForKycProcessClientInformation, codecForKycProcessStartInformation, codecForLegitimizationNeededResponse, @@ -216,7 +216,7 @@ export class TalerExchangeHttpClient { }); switch (resp.status) { case HttpStatusCode.Ok: - return opSuccessFromHttp(resp, codecForExchangeKeys()); + return opSuccessFromHttp(resp, codecForExchangeKeysResponse()); default: return opUnknownFailure(resp, await readTalerErrorResponse(resp)); } diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts @@ -27,7 +27,6 @@ import { codecOptional, } from "./codec.js"; import { - PaytoString, buildCodecForUnion, codecForAmountString, codecForBoolean, @@ -67,8 +66,6 @@ import { Timestamp, WireSalt, codecForAccessToken, - codecForEddsaPublicKey, - codecForEddsaSignature, codecForInternationalizedString, codecForURLString, } from "./types-taler-common.js"; @@ -400,16 +397,27 @@ export interface Recoup { /** * Structure that the exchange gives us in /keys. */ -export interface ExchangeKeysJson { +export interface ExchangeKeysResponse { /** * Canonical, public base URL of the exchange. */ base_url: string; + /** + * The exchange's currency or asset unit. + */ currency: string; + /** + * Type of the asset. "fiat", "crypto", "regional" + * or "stock". Wallets should adjust their UI/UX + * based on this value. + */ asset_type: string; + /** + * How wallets should render the exchange's currency. + */ currency_specification?: CurrencySpecification; /** @@ -507,6 +515,32 @@ export interface ExchangeKeysJson { // explicitly as the client might otherwise be confused by clock skew as to // which signing key was used for the exchange_sig. exchange_pub: EddsaPublicKey; + + // Optional field with a dictionary of (name, object) pairs defining the + // supported and enabled extensions, such as age_restriction. + extensions?: { name: ExtensionManifest }; + + // Signature by the exchange master key of the SHA-256 hash of the + // normalized JSON-object of field extensions, if it was set. + // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS. + extensions_sig?: EddsaSignature; + + // Set to true if this exchange has KYC enabled and thus + // requires KYC auth wire transfers prior to a first deposit. + // @since in protocol **v24**. + kyc_enabled: boolean; + + // Shopping URL where users may find shops that accept + // digital cash issued by this exchange. + // @since protocol **v21**. + shopping_url?: string; + + // Small(est?) amount that can likely be transferred to + // the exchange. Should be the default amount for KYC + // authentication wire transfers to this exchange. + // Optional, not present if not known or not configured. + // @since protocol **v21**. + tiny_amount?: Amount; } export interface ExchangeMeltRequest { @@ -749,6 +783,7 @@ export interface ExchangeWireAccount { // bank account. // Since protocol **v19**. bank_label?: string; + priority?: number; } @@ -912,47 +947,6 @@ export const codecForGlobalFees = (): Codec<GlobalFees> => // FIXME: Validate properly! export const codecForNgDenominations: Codec<DenomGroup> = codecForAny(); -export const codecForExchangeKeysJson = (): Codec<ExchangeKeysJson> => - buildCodecForObject<ExchangeKeysJson>() - .property("base_url", codecForString()) - .property("currency", codecForString()) - .property( - "currency_specification", - codecOptional(codecForCurrencySpecificiation()), - ) - .property("master_public_key", codecForString()) - .property("auditors", codecForList(codecForAuditor())) - .property("list_issue_date", codecForTimestamp) - .property("recoup", codecOptional(codecForList(codecForRecoup()))) - .property("signkeys", codecForList(codecForExchangeSigningKey())) - .property("version", codecForString()) - .property("reserve_closing_delay", codecForDuration) - .property("global_fees", codecForList(codecForGlobalFees())) - .property("accounts", codecForList(codecForExchangeWireAccount())) - .property("wire_fees", codecForMap(codecForList(codecForWireFeesJson()))) - .property( - "zero_limits", - codecOptional(codecForList(codecForZeroLimitedOperation())), - ) - .property( - "hard_limits", - codecOptional(codecForList(codecForAccountLimit())), - ) - .property("denominations", codecForList(codecForNgDenominations)) - .property( - "wallet_balance_limit_without_kyc", - codecOptional(codecForList(codecForAmountString())), - ) - .property("stefan_abs", codecForAmountString()) - .property("stefan_log", codecForAmountString()) - .property("stefan_lin", codecForNumber()) - .property("wads", codecForAny()) - .deprecatedProperty("rewards_allowed") - .property("exchange_pub", codecForEddsaPublicKey()) - .property("exchange_sig", codecForEddsaSignature()) - .property("asset_type", codecForString()) - .build("ExchangeKeysJson"); - export const codecForWireFeesJson = (): Codec<WireFeesJson> => buildCodecForObject<WireFeesJson>() .property("wire_fee", codecForAmountString()) @@ -1647,31 +1641,6 @@ export interface ExchangeVersionResponse { aml_spa_dialect?: AmlSpaDialect; } -export interface WireAccount { - // payto:// URI identifying the account and wire method - payto_uri: PaytoString; - - // URI to convert amounts from or to the currency used by - // this wire account of the exchange. Missing if no - // conversion is applicable. - conversion_url?: string; - - // Restrictions that apply to bank accounts that would send - // funds to the exchange (crediting this exchange bank account). - // Optional, empty array for unrestricted. - credit_restrictions: AccountRestriction[]; - - // Restrictions that apply to bank accounts that would receive - // funds from the exchange (debiting this exchange bank account). - // Optional, empty array for unrestricted. - debit_restrictions: AccountRestriction[]; - - // Signature using the exchange's offline key over - // a TALER_MasterWireDetailsPS - // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. - master_sig: EddsaSignatureString; -} - export interface WalletKycRequest { // Balance threshold (not necessarily exact balance) // to be crossed by the wallet that (may) trigger @@ -2097,147 +2066,6 @@ export enum AmlState { } type Float = number; -export interface ExchangeKeysResponse { - // libtool-style representation of the Exchange protocol version, see - // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning - // The format is "current:revision:age". - version: string; - - // The exchange's base URL. - base_url: string; - - // The exchange's currency or asset unit. - currency: string; - - // How wallets should render this currency. - currency_specification: CurrencySpecification; - - // Absolute cost offset for the STEFAN curve used - // to (over) approximate fees payable by amount. - stefan_abs: AmountString; - - // Factor to multiply the logarithm of the amount - // with to (over) approximate fees payable by amount. - // Note that the total to be paid is first to be - // divided by the smallest denomination to obtain - // the value that the logarithm is to be taken of. - stefan_log: AmountString; - - // Linear cost factor for the STEFAN curve used - // to (over) approximate fees payable by amount. - // - // Note that this is a scalar, as it is multiplied - // with the actual amount. - stefan_lin: Float; - - // Type of the asset. "fiat", "crypto", "regional" - // or "stock". Wallets should adjust their UI/UX - // based on this value. - asset_type: string; - - // Array of wire accounts operated by the exchange for - // incoming wire transfers. - accounts: WireAccount[]; - - // Object mapping names of wire methods (i.e. "iban" or "x-taler-bank") - // to wire fees. - wire_fees: { method: AggregateTransferFee[] }; - - // List of exchanges that this exchange is partnering - // with to enable wallet-to-wallet transfers. - wads: ExchangePartnerListEntry[]; - - // EdDSA master public key of the exchange, used to sign entries - // in denoms and signkeys. - master_public_key: EddsaPublicKey; - - // Relative duration until inactive reserves are closed; - // not signed (!), can change without notice. - reserve_closing_delay: RelativeTime; - - // Threshold amounts beyond which wallet should - // trigger the KYC process of the issuing exchange. - // Optional option, if not given there is no limit. - // Currency must match currency. - wallet_balance_limit_without_kyc?: AmountString[]; - - // Array of limits that apply to all accounts. - // All of the given limits will be hard limits. - // Wallets and merchants are expected to obey them - // and not even allow the user to cross them. - // Since protocol **v21**. - hard_limits: AccountLimit[]; - - // Array of limits with a soft threshold of zero - // that apply to all accounts without KYC. - // Wallets and merchants are expected to trigger - // a KYC process before attempting any zero-limited - // operations. - // Since protocol **v21**. - zero_limits: ZeroLimitedOperation[]; - - // Denominations offered by this exchange - denominations: DenomGroup[]; - - // Compact EdDSA signature (binary-only) over the - // contatentation of all of the master_sigs (in reverse - // chronological order by group) in the arrays under - // "denominations". Signature of TALER_ExchangeKeySetPS - exchange_sig: EddsaSignature; - - // Public EdDSA key of the exchange that was used to generate the signature. - // Should match one of the exchange's signing keys from signkeys. It is given - // explicitly as the client might otherwise be confused by clock skew as to - // which signing key was used for the exchange_sig. - exchange_pub: EddsaPublicKey; - - // Denominations for which the exchange currently offers/requests recoup. - recoup: Recoup[]; - - // Array of globally applicable fees by time range. - global_fees: GlobalFees[]; - - // The date when the denomination keys were last updated. - list_issue_date: Timestamp; - - // Auditors of the exchange. - auditors: AuditorKeys[]; - - // The exchange's signing keys. - signkeys: SignKey[]; - - // Optional field with a dictionary of (name, object) pairs defining the - // supported and enabled extensions, such as age_restriction. - extensions?: { name: ExtensionManifest }; - - // Signature by the exchange master key of the SHA-256 hash of the - // normalized JSON-object of field extensions, if it was set. - // The signature has purpose TALER_SIGNATURE_MASTER_EXTENSIONS. - extensions_sig?: EddsaSignature; - - // Set to true if this exchange has KYC enabled and thus - // requires KYC auth wire transfers prior to a first deposit. - // @since in protocol **v24**. - kyc_enabled: boolean; - - // Set to true if this exchange allows the use - // of reserves for rewards. - // @deprecated in protocol **v18**. - // rewards_allowed: false; - - // Shopping URL where users may find shops that accept - // digital cash issued by this exchange. - // @since protocol **v21**. - shopping_url?: string; - - // Small(est?) amount that can likely be transferred to - // the exchange. Should be the default amount for KYC - // authentication wire transfers to this exchange. - // Optional, not present if not known or not configured. - // @since protocol **v21**. - tiny_amount?: AmountString; -} - export interface ZeroLimitedOperation { // Operation that is limited to an amount of // zero until the client has passed some KYC check. @@ -2462,7 +2290,7 @@ export const codecForExchangeConfig = (): Codec<ExchangeVersionResponse> => .build("TalerExchangeApi.ExchangeVersionResponse"); // FIXME: complete the codec to check for valid exchange response -export const codecForExchangeKeys = (): Codec<ExchangeKeysResponse> => +export const codecForExchangeKeysResponse = (): Codec<ExchangeKeysResponse> => buildCodecForObject<ExchangeKeysResponse>() .property("version", codecForString()) .property("base_url", codecForString()) diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts @@ -98,7 +98,7 @@ import { checkDbInvariant, checkLogicInvariant, codecForAccountKycStatus, - codecForExchangeKeysJson, + codecForExchangeKeysResponse, codecForLegitimizationNeededResponse, durationMul, encodeCrock, @@ -949,12 +949,12 @@ async function downloadExchangeKeysInfo( ); } - const exchangeKeysJsonUnchecked = await readSuccessResponseJsonOrThrow( + const ExchangeKeysResponseUnchecked = await readSuccessResponseJsonOrThrow( resp, - codecForExchangeKeysJson(), + codecForExchangeKeysResponse(), ); - if (exchangeKeysJsonUnchecked.denominations.length === 0) { + if (ExchangeKeysResponseUnchecked.denominations.length === 0) { throw TalerError.fromDetail( TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT, { @@ -964,11 +964,11 @@ async function downloadExchangeKeysInfo( ); } - const currency = exchangeKeysJsonUnchecked.currency; + const currency = ExchangeKeysResponseUnchecked.currency; const currentDenominations: DenominationRecord[] = []; - for (const denomGroup of exchangeKeysJsonUnchecked.denominations) { + for (const denomGroup of ExchangeKeysResponseUnchecked.denominations) { switch (denomGroup.cipher) { case "RSA": case "RSA+age_restricted": { @@ -988,7 +988,7 @@ async function downloadExchangeKeysInfo( denomPub, denomPubHash, exchangeBaseUrl: baseUrl, - exchangeMasterPub: exchangeKeysJsonUnchecked.master_public_key, + exchangeMasterPub: ExchangeKeysResponseUnchecked.master_public_key, isOffered: true, isRevoked: false, isLost: denomIn.lost ?? false, @@ -1028,29 +1028,29 @@ async function downloadExchangeKeysInfo( } return { - masterPublicKey: exchangeKeysJsonUnchecked.master_public_key, + masterPublicKey: ExchangeKeysResponseUnchecked.master_public_key, currency, - baseUrl: exchangeKeysJsonUnchecked.base_url, - auditors: exchangeKeysJsonUnchecked.auditors, + baseUrl: ExchangeKeysResponseUnchecked.base_url, + auditors: ExchangeKeysResponseUnchecked.auditors, currentDenominations, - protocolVersion: exchangeKeysJsonUnchecked.version, - signingKeys: exchangeKeysJsonUnchecked.signkeys, - reserveClosingDelay: exchangeKeysJsonUnchecked.reserve_closing_delay, + protocolVersion: ExchangeKeysResponseUnchecked.version, + signingKeys: ExchangeKeysResponseUnchecked.signkeys, + reserveClosingDelay: ExchangeKeysResponseUnchecked.reserve_closing_delay, expiry: AbsoluteTime.toProtocolTimestamp( getExpiry(resp, { minDuration: Duration.fromSpec({ hours: 1 }), }), ), - recoup: exchangeKeysJsonUnchecked.recoup ?? [], - listIssueDate: exchangeKeysJsonUnchecked.list_issue_date, - globalFees: exchangeKeysJsonUnchecked.global_fees, - accounts: exchangeKeysJsonUnchecked.accounts, - wireFees: exchangeKeysJsonUnchecked.wire_fees, - currencySpecification: exchangeKeysJsonUnchecked.currency_specification, + recoup: ExchangeKeysResponseUnchecked.recoup ?? [], + listIssueDate: ExchangeKeysResponseUnchecked.list_issue_date, + globalFees: ExchangeKeysResponseUnchecked.global_fees, + accounts: ExchangeKeysResponseUnchecked.accounts, + wireFees: ExchangeKeysResponseUnchecked.wire_fees, + currencySpecification: ExchangeKeysResponseUnchecked.currency_specification, walletBalanceLimits: - exchangeKeysJsonUnchecked.wallet_balance_limit_without_kyc, - hardLimits: exchangeKeysJsonUnchecked.hard_limits, - zeroLimits: exchangeKeysJsonUnchecked.zero_limits, + ExchangeKeysResponseUnchecked.wallet_balance_limit_without_kyc, + hardLimits: ExchangeKeysResponseUnchecked.hard_limits, + zeroLimits: ExchangeKeysResponseUnchecked.zero_limits, }; }