commit 861c27f9c866717e4c764fb9e9ddeb2fb0d97459
parent ccad582b4380ac4344cb231b95072743e3d20909
Author: Florian Dold <florian@dold.me>
Date: Mon, 27 Jan 2025 12:06:45 +0100
fix duplicate message definition
Diffstat:
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,
};
}