fixing tos request

This commit is contained in:
Sebastian 2021-10-13 14:26:18 -03:00
parent 021d508337
commit fbf501e727
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
9 changed files with 220 additions and 196 deletions

View File

@ -578,7 +578,7 @@ export interface GetExchangeTosResult {
/**
* Markdown version of the current ToS.
*/
tos: string;
content: string;
/**
* Version tag of the current ToS.
@ -590,6 +590,11 @@ export interface GetExchangeTosResult {
* if any.
*/
acceptedEtag: string | undefined;
/**
* Accepted content type
*/
contentType: string;
}
export interface TestPayArgs {
@ -648,11 +653,13 @@ export const codecForForceExchangeUpdateRequest = (): Codec<AddExchangeRequest>
export interface GetExchangeTosRequest {
exchangeBaseUrl: string;
acceptedFormat?: string[];
}
export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
buildCodecForObject<GetExchangeTosRequest>()
.property("exchangeBaseUrl", codecForString())
.property("acceptedFormat", codecOptional(codecForList(codecForString())))
.build("GetExchangeTosRequest");
export interface AcceptManualWithdrawalRequest {

View File

@ -71,6 +71,7 @@ export interface ExchangeOperations {
updateExchangeFromUrl(
ws: InternalWalletState,
baseUrl: string,
acceptedFormat?: string[],
forceNow?: boolean,
): Promise<{
exchange: ExchangeRecord;

View File

@ -278,6 +278,7 @@ async function downloadExchangeWithWireInfo(
export async function updateExchangeFromUrl(
ws: InternalWalletState,
baseUrl: string,
acceptedFormat?: string[],
forceNow = false,
): Promise<{
exchange: ExchangeRecord;
@ -286,7 +287,7 @@ export async function updateExchangeFromUrl(
const onOpErr = (e: TalerErrorDetails): Promise<void> =>
handleExchangeUpdateError(ws, baseUrl, e);
return await guardOperationException(
() => updateExchangeFromUrlImpl(ws, baseUrl, forceNow),
() => updateExchangeFromUrlImpl(ws, baseUrl, acceptedFormat, forceNow),
onOpErr,
);
}
@ -411,6 +412,7 @@ async function downloadKeysInfo(
async function updateExchangeFromUrlImpl(
ws: InternalWalletState,
baseUrl: string,
acceptedFormat?: string[],
forceNow = false,
): Promise<{
exchange: ExchangeRecord;
@ -468,7 +470,23 @@ async function updateExchangeFromUrlImpl(
logger.info("finished validating exchange /wire info");
const tosDownload = await downloadExchangeWithTermsOfService(
let tosFound: ExchangeTosDownloadResult | undefined;
//Remove this when exchange supports multiple content-type in accept header
if (acceptedFormat) for (const format of acceptedFormat) {
const resp = await downloadExchangeWithTermsOfService(
baseUrl,
ws.http,
timeout,
format
);
if (resp.tosContentType === format) {
tosFound = resp
break
}
}
// If none of the specified format was found try text/plain
const tosDownload = tosFound !== undefined ? tosFound :
await downloadExchangeWithTermsOfService(
baseUrl,
ws.http,
timeout,

View File

@ -920,7 +920,7 @@ export async function autoRefresh(
exchangeBaseUrl: string,
): Promise<void> {
logger.info(`doing auto-refresh check for '${exchangeBaseUrl}'`);
await updateExchangeFromUrl(ws, exchangeBaseUrl, true);
await updateExchangeFromUrl(ws, exchangeBaseUrl, undefined, true);
let minCheckThreshold = timestampAddDuration(
getTimestampNow(),
durationFromSpec({ days: 1 }),

View File

@ -66,8 +66,6 @@ import {
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION,
} from "../versions.js";
import { stringify } from "querystring";
import { downloadExchangeWithTermsOfService, ExchangeTosDownloadResult } from "./exchanges";
/**
* Logger for this file.
@ -133,11 +131,6 @@ export interface ExchangeWithdrawDetails {
*/
termsOfServiceAccepted: boolean;
/**
* Tos
*/
tosRequested: ExchangeTosDownloadResult | undefined
/**
* The exchange is trusted directly.
*/
@ -937,7 +930,6 @@ export async function getExchangeWithdrawalInfo(
ws: InternalWalletState,
baseUrl: string,
amount: AmountJson,
tosAcceptedFormat?: string[],
): Promise<ExchangeWithdrawDetails> {
const {
exchange,
@ -1004,34 +996,6 @@ export async function getExchangeWithdrawalInfo(
}
}
const noTosDownloaded =
exchangeDetails.termsOfServiceContentType === undefined ||
exchangeDetails.termsOfServiceAcceptedEtag === undefined ||
exchangeDetails.termsOfServiceText === undefined;
let tosFound: ExchangeTosDownloadResult | undefined = noTosDownloaded ? undefined : {
tosContentType: exchangeDetails.termsOfServiceContentType!,
tosEtag: exchangeDetails.termsOfServiceAcceptedEtag!,
tosText: exchangeDetails.termsOfServiceText!,
};
try {
if (tosAcceptedFormat) for (const format of tosAcceptedFormat) {
const resp = await downloadExchangeWithTermsOfService(
exchangeDetails.exchangeBaseUrl,
ws.http,
{ d_ms: 1000 },
format
);
if (resp.tosContentType === format) {
tosFound = resp
break
}
}
} catch (e) {
tosFound = undefined
}
const withdrawFee = Amounts.sub(
selectedDenoms.totalWithdrawCost,
selectedDenoms.totalCoinValue,
@ -1054,7 +1018,6 @@ export async function getExchangeWithdrawalInfo(
walletVersion: WALLET_EXCHANGE_PROTOCOL_VERSION,
withdrawFee,
termsOfServiceAccepted: tosAccepted,
tosRequested: tosFound
};
return ret;
}

View File

@ -217,7 +217,7 @@ async function processOnePendingOperation(
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
switch (pending.type) {
case PendingTaskType.ExchangeUpdate:
await updateExchangeFromUrl(ws, pending.exchangeBaseUrl, forceNow);
await updateExchangeFromUrl(ws, pending.exchangeBaseUrl, undefined, forceNow);
break;
case PendingTaskType.Refresh:
await processRefreshGroup(ws, pending.refreshGroupId, forceNow);
@ -452,20 +452,24 @@ async function acceptManualWithdrawal(
async function getExchangeTos(
ws: InternalWalletState,
exchangeBaseUrl: string,
acceptedFormat?: string[],
): Promise<GetExchangeTosResult> {
const { exchange, exchangeDetails } = await updateExchangeFromUrl(
const { exchangeDetails } = await updateExchangeFromUrl(
ws,
exchangeBaseUrl,
acceptedFormat,
);
const tos = exchangeDetails.termsOfServiceText;
const content = exchangeDetails.termsOfServiceText;
const currentEtag = exchangeDetails.termsOfServiceLastEtag;
if (!tos || !currentEtag) {
const contentType = exchangeDetails.termsOfServiceContentType;
if (content === undefined || currentEtag === undefined || contentType === undefined) {
throw Error("exchange is in invalid state");
}
return {
acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag,
currentEtag,
tos,
content,
contentType,
};
}
@ -485,7 +489,7 @@ async function getExchanges(
if (!dp) {
continue;
}
const { currency, masterPublicKey } = dp;
const { currency } = dp;
const exchangeDetails = await getExchangeDetails(tx, r.baseUrl);
if (!exchangeDetails) {
continue;
@ -684,7 +688,7 @@ async function dispatchRequestInternal(
}
case "addExchange": {
const req = codecForAddExchangeRequest().decode(payload);
await updateExchangeFromUrl(ws, req.exchangeBaseUrl, req.forceUpdate);
await updateExchangeFromUrl(ws, req.exchangeBaseUrl, undefined, req.forceUpdate);
return {};
}
case "listExchanges": {
@ -696,7 +700,7 @@ async function dispatchRequestInternal(
}
case "getExchangeWithdrawalInfo": {
const req = codecForGetExchangeWithdrawalInfo().decode(payload);
return await getExchangeWithdrawalInfo(ws, req.exchangeBaseUrl, req.amount, req.tosAcceptedFormat);
return await getExchangeWithdrawalInfo(ws, req.exchangeBaseUrl, req.amount);
}
case "acceptManualWithdrawal": {
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
@ -744,7 +748,7 @@ async function dispatchRequestInternal(
}
case "getExchangeTos": {
const req = codecForGetExchangeTosRequest().decode(payload);
return getExchangeTos(ws, req.exchangeBaseUrl);
return getExchangeTos(ws, req.exchangeBaseUrl , req.acceptedFormat);
}
case "retryPendingNow": {
await runPending(ws, true);

View File

@ -790,16 +790,18 @@ export const NewTerms = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -826,16 +828,18 @@ export const TermsReviewingPLAIN = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -863,16 +867,18 @@ export const TermsReviewingHTML = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -915,16 +921,18 @@ export const TermsReviewingPDF = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -953,16 +961,18 @@ export const TermsReviewingXML = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -990,16 +1000,18 @@ export const NewTermsAccepted = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -1026,16 +1038,18 @@ export const TermsShowAgainXML = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -1050,6 +1064,7 @@ export const TermsShowAgainXML = createExample(TestedComponent, {
},
status: 'new'
},
reviewed: true,
reviewing: true,
})
@ -1063,16 +1078,18 @@ export const TermsChanged = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -1099,16 +1116,18 @@ export const TermsNotFound = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -1131,16 +1150,18 @@ export const TermsAlreadyAccepted = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: amountFractionalBase * 0.5,
value: 0
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,
@ -1164,16 +1185,18 @@ export const WithoutFee = createExample(TestedComponent, {
exchangeBaseUrl: 'exchange.test.taler.net',
paytoUris: ['asd'],
}],
exchangeBaseUrl: 'exchange.demo.taler.net',
details: {
exchangeInfo: {
baseUrl: 'exchange.demo.taler.net'
} as ExchangeRecord,
withdrawFee: {
content: '',
contentType: '',
currentEtag: '',
acceptedEtag: undefined,
},
withdrawalFee: {
currency: 'USD',
fraction: 0,
value: 0
value: 0,
},
} as ExchangeWithdrawDetails,
amount: {
currency: 'USD',
value: 2,

View File

@ -21,7 +21,7 @@
* @author Florian Dold
*/
import { AmountJson, Amounts, ExchangeListItem, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util';
import { AmountJson, Amounts, ExchangeListItem, GetExchangeTosResult, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util';
import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw';
import { useState } from "preact/hooks";
import { Fragment } from 'preact/jsx-runtime';
@ -33,7 +33,7 @@ import { SelectList } from '../components/SelectList';
import { ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction } from '../components/styled';
import { useAsyncAsHook } from '../hooks/useAsyncAsHook';
import {
acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges
acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges, getExchangeTos
} from "../wxApi";
import { wxMain } from '../wxBackend.js';
@ -42,7 +42,9 @@ interface Props {
}
export interface ViewProps {
details: ExchangeWithdrawDetails;
details: GetExchangeTosResult;
withdrawalFee: AmountJson;
exchangeBaseUrl: string;
amount: AmountJson;
onSwitchExchange: (ex: string) => void;
onWithdraw: () => Promise<void>;
@ -54,8 +56,8 @@ export interface ViewProps {
terms: {
value?: TermsDocument;
status: TermsStatus;
},
knownExchanges: ExchangeListItem[]
};
knownExchanges: ExchangeListItem[];
};
@ -94,7 +96,7 @@ function amountToString(text: AmountJson) {
return `${amount} ${aj.currency}`
}
export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) {
export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) {
const needsReview = terms.status === 'changed' || terms.status === 'new'
const [switchingExchange, setSwitchingExchange] = useState<string | undefined>(undefined)
@ -107,12 +109,12 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
{i18n.str`Digital cash withdrawal`}
</h2>
<section>
<Part title="Total to withdraw" text={amountToString(Amounts.sub(amount, details.withdrawFee).amount)} kind='positive' />
<Part title="Total to withdraw" text={amountToString(Amounts.sub(amount, withdrawalFee).amount)} kind='positive' />
<Part title="Chosen amount" text={amountToString(amount)} kind='neutral' />
{Amounts.isNonZero(details.withdrawFee) &&
<Part title="Exchange fee" text={amountToString(details.withdrawFee)} kind='negative' />
{Amounts.isNonZero(withdrawalFee) &&
<Part title="Exchange fee" text={amountToString(withdrawalFee)} kind='negative' />
}
<Part title="Exchange" text={details.exchangeInfo.baseUrl} kind='neutral' big />
<Part title="Exchange" text={exchangeBaseUrl} kind='neutral' big />
</section>
{!reviewing &&
<section>
@ -190,7 +192,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
{terms.status === 'new' && !reviewed && !reviewing &&
<ButtonSuccess
upperCased
disabled={!details.exchangeInfo.baseUrl}
disabled={!exchangeBaseUrl}
onClick={() => onReview(true)}
>
{i18n.str`Review exchange terms of service`}
@ -199,7 +201,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
{terms.status === 'changed' && !reviewed && !reviewing &&
<ButtonWarning
upperCased
disabled={!details.exchangeInfo.baseUrl}
disabled={!exchangeBaseUrl}
onClick={() => onReview(true)}
>
{i18n.str`Review new version of terms of service`}
@ -208,7 +210,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
{(terms.status === 'accepted' || (needsReview && reviewed)) &&
<ButtonSuccess
upperCased
disabled={!details.exchangeInfo.baseUrl || confirmed}
disabled={!exchangeBaseUrl || confirmed}
onClick={onWithdraw}
>
{i18n.str`Confirm withdrawal`}
@ -220,7 +222,7 @@ export function View({ details, knownExchanges, amount, onWithdraw, onSwitchExch
</LinkWarning>
<ButtonWarning
upperCased
disabled={!details.exchangeInfo.baseUrl}
disabled={!exchangeBaseUrl}
onClick={onWithdraw}
>
{i18n.str`Withdraw anyway`}
@ -249,11 +251,13 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
const exchange = customExchange || uriInfo.defaultExchangeBaseUrl || thisCurrencyExchanges[0]?.exchangeBaseUrl
const detailsHook = useAsyncAsHook(async () => {
if (!exchange) throw Error('no default exchange')
return getExchangeWithdrawalInfo({
const tos = await getExchangeTos(exchange, ['text/xml'])
const info = await getExchangeWithdrawalInfo({
exchangeBaseUrl: exchange,
amount: withdrawAmount,
tosAcceptedFormat: ['text/xml']
})
return {tos, info}
})
if (!detailsHook) {
@ -267,7 +271,7 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
const onAccept = async (): Promise<void> => {
try {
await setExchangeTosAccepted(details.exchangeInfo.baseUrl, details.tosRequested?.tosEtag)
await setExchangeTosAccepted(exchange, details.tos.currentEtag)
setReviewed(true)
} catch (e) {
if (e instanceof Error) {
@ -278,9 +282,9 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
const onWithdraw = async (): Promise<void> => {
setConfirmed(true)
console.log("accepting exchange", details.exchangeDetails.exchangeBaseUrl);
console.log("accepting exchange", exchange);
try {
const res = await acceptWithdrawal(uri, details.exchangeInfo.baseUrl);
const res = await acceptWithdrawal(uri, exchange);
console.log("accept withdrawal response", res);
if (res.confirmTransferUrl) {
document.location.href = res.confirmTransferUrl;
@ -290,17 +294,18 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
}
};
const termsContent: TermsDocument | undefined = !details.tosRequested ? undefined : parseTermsOfServiceContent(details.tosRequested.tosContentType, details.tosRequested.tosText);
const termsContent: TermsDocument | undefined = parseTermsOfServiceContent(details.tos.contentType, details.tos.content);
const status: TermsStatus = !termsContent ? 'notfound' : (
!details.exchangeDetails.termsOfServiceAcceptedEtag ? 'new' : (
details.tosRequested?.tosEtag !== details.exchangeDetails.termsOfServiceAcceptedEtag ? 'changed' : 'accepted'
!details.tos.acceptedEtag ? 'new' : (
details.tos.acceptedEtag !== details.tos.currentEtag ? 'changed' : 'accepted'
))
return <View onWithdraw={onWithdraw}
// setCancelled={setCancelled} setSelecting={setSelecting}
details={details} amount={withdrawAmount}
details={details.tos} amount={withdrawAmount}
exchangeBaseUrl={exchange}
withdrawalFee={details.info.withdrawFee} //FIXME
terms={{
status, value: termsContent
}}
@ -309,7 +314,6 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
confirmed={confirmed}
reviewed={reviewed} onAccept={onAccept}
reviewing={reviewing} onReview={setReviewing}
// terms={[]}
/>
}
export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element {

View File

@ -45,6 +45,7 @@ import {
AmountJson,
ExchangesListRespose,
AddExchangeRequest,
GetExchangeTosResult,
} from "@gnu-taler/taler-util";
import { AddBackupProviderRequest, BackupProviderState, OperationFailedError, RemoveBackupProviderRequest } from "@gnu-taler/taler-wallet-core";
import { BackupInfo } from "@gnu-taler/taler-wallet-core";
@ -327,11 +328,14 @@ export function getExchangeWithdrawalInfo(
): Promise<ExchangeWithdrawDetails> {
return callBackend("getExchangeWithdrawalInfo", req);
}
// export const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
// buildCodecForObject<AddExchangeRequest>()
// .property("exchangeBaseUrl", codecForString())
// .property("forceUpdate", codecOptional(codecForBoolean()))
// .build("AddExchangeRequest");
export function getExchangeTos(
exchangeBaseUrl: string,
acceptedFormat: string[],
): Promise<GetExchangeTosResult> {
return callBackend("getExchangeTos", {
exchangeBaseUrl, acceptedFormat
});
}
export function addExchange(
req: AddExchangeRequest,