commit 1ec9a91ccc5713a0966cb50fc35d1560d1906f17
parent 4748841815f035fbfccfc89b599abde8b48cc789
Author: Florian Dold <florian@dold.me>
Date: Fri, 14 Mar 2025 15:03:10 +0100
wallet-core: allow passing taler URI when adding exchange
Diffstat:
4 files changed, 69 insertions(+), 10 deletions(-)
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -1840,6 +1840,16 @@ export interface GetExchangeEntryByUrlRequest {
exchangeBaseUrl: string;
}
+export const codecForGetExchangeDetailedInfoRequest =
+ (): Codec<GetExchangeDetailedInfoRequest> =>
+ buildCodecForObject<GetExchangeDetailedInfoRequest>()
+ .property("exchangeBaseUrl", codecForCanonBaseUrl())
+ .build("GetExchangeDetailedInfoRequest");
+
+export interface GetExchangeDetailedInfoRequest {
+ exchangeBaseUrl: string;
+}
+
export const codecForGetExchangeEntryByUrlRequest =
(): Codec<GetExchangeEntryByUrlRequest> =>
buildCodecForObject<GetExchangeEntryByUrlRequest>()
@@ -1849,7 +1859,16 @@ export const codecForGetExchangeEntryByUrlRequest =
export type GetExchangeEntryByUrlResponse = ExchangeListItem;
export interface AddExchangeRequest {
- exchangeBaseUrl: string;
+ /**
+ * @deprecated Use {@link uri} instead
+ */
+ exchangeBaseUrl?: string;
+
+ /**
+ * Either an http(s) exchange base URL or
+ * a taler://add-exchange/ URI.
+ */
+ uri?: string;
ephemeral?: boolean;
@@ -1859,9 +1878,17 @@ export interface AddExchangeRequest {
forceUpdate?: boolean;
}
+export interface AddExchangeResponse {
+ /**
+ * Base URL of the exchange that was added to the wallet.
+ */
+ exchangeBaseUrl: string;
+}
+
export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
buildCodecForObject<AddExchangeRequest>()
- .property("exchangeBaseUrl", codecForCanonBaseUrl())
+ .property("exchangeBaseUrl", codecOptional(codecForCanonBaseUrl()))
+ .property("uri", codecOptional(codecForString()))
.property("forceUpdate", codecOptional(codecForBoolean()))
.property("ephemeral", codecOptional(codecForBoolean()))
.build("AddExchangeRequest");
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
@@ -899,7 +899,7 @@ exchangesCli
.action(async (args) => {
await withWallet(args, { lazyTaskLoop: true }, async (wallet) => {
await wallet.client.call(WalletApiOperation.AddExchange, {
- exchangeBaseUrl: args.exchangesAddCmd.url,
+ uri: args.exchangesAddCmd.url,
});
});
});
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -35,6 +35,7 @@ import {
AddBankAccountRequest,
AddBankAccountResponse,
AddExchangeRequest,
+ AddExchangeResponse,
AddGlobalCurrencyAuditorRequest,
AddGlobalCurrencyExchangeRequest,
AmountResponse,
@@ -86,6 +87,7 @@ import {
GetDepositWireTypesForCurrencyResponse,
GetDepositWireTypesRequest,
GetDepositWireTypesResponse,
+ GetExchangeDetailedInfoRequest,
GetExchangeEntryByUrlRequest,
GetExchangeEntryByUrlResponse,
GetExchangeResourcesRequest,
@@ -705,7 +707,7 @@ export type PrepareWithdrawExchangeOp = {
export type AddExchangeOp = {
op: WalletApiOperation.AddExchange;
request: AddExchangeRequest;
- response: EmptyObject;
+ response: AddExchangeResponse;
};
/**
@@ -791,7 +793,7 @@ export type GetDepositWireTypesForCurrencyOp = {
*/
export type GetExchangeDetailedInfoOp = {
op: WalletApiOperation.GetExchangeDetailedInfo;
- request: AddExchangeRequest;
+ request: GetExchangeDetailedInfoRequest;
response: ExchangeDetailedResponse;
};
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
@@ -38,6 +38,7 @@ import {
AddBankAccountRequest,
AddBankAccountResponse,
AddExchangeRequest,
+ AddExchangeResponse,
AddGlobalCurrencyAuditorRequest,
AddGlobalCurrencyExchangeRequest,
AmountJson,
@@ -929,16 +930,45 @@ async function handleValidateIban(
async function handleAddExchange(
wex: WalletExecutionContext,
req: AddExchangeRequest,
-): Promise<EmptyObject> {
- await fetchFreshExchange(wex, req.exchangeBaseUrl, {});
+): Promise<AddExchangeResponse> {
+ let exchangeBaseUrl: string;
+ if (req.exchangeBaseUrl) {
+ logger.warn(
+ "Deprecated request property: AddExchangeRequest.exchangeBaseUrl",
+ );
+ exchangeBaseUrl = req.exchangeBaseUrl;
+ } else if (req.uri) {
+ if (req.uri.startsWith("http")) {
+ const canonUrl = canonicalizeBaseUrl(req.uri);
+ if (req.uri != canonUrl) {
+ throw Error("exchange base URL must be canonicalized");
+ }
+ exchangeBaseUrl = req.uri;
+ } else if (req.uri.startsWith("taler")) {
+ const p = parseTalerUri(req.uri);
+ if (p?.type !== TalerUriAction.AddExchange) {
+ throw Error("invalid taler://add-exchange/ URI");
+ }
+ exchangeBaseUrl = p.exchangeBaseUrl;
+ } else {
+ throw Error("AddExchangeRequest.uri must be http(s) or taler URI");
+ }
+ } else {
+ throw Error(
+ "AddExchangeRequest must either specify uri or exchangeBaseUrl",
+ );
+ }
+ await fetchFreshExchange(wex, exchangeBaseUrl, {});
// Exchange has been explicitly added upon user request.
// Thus, we mark it as "used".
if (!req.ephemeral) {
await wex.db.runAllStoresReadWriteTx({}, async (tx) => {
- await markExchangeUsed(wex, tx, req.exchangeBaseUrl);
+ await markExchangeUsed(wex, tx, exchangeBaseUrl);
});
}
- return {};
+ return {
+ exchangeBaseUrl,
+ };
}
async function handleUpdateExchangeEntry(
@@ -1793,7 +1823,7 @@ const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = {
handler: lookupExchangeByUri,
},
[WalletApiOperation.GetExchangeDetailedInfo]: {
- codec: codecForAddExchangeRequest(),
+ codec: codecForGetExchangeEntryByUrlRequest(),
handler: (wex, req) => getExchangeDetailedInfo(wex, req.exchangeBaseUrl),
},
[WalletApiOperation.ListBankAccounts]: {