wallet-core: get rid of duplicated withdrawal info API
This commit is contained in:
parent
da9ec5eb16
commit
6acddd6d70
@ -68,6 +68,7 @@ import { BackupRecovery } from "./backupTypes.js";
|
||||
import { PaytoUri } from "./payto.js";
|
||||
import { TalerErrorCode } from "./taler-error-codes.js";
|
||||
import { AgeCommitmentProof } from "./talerCrypto.js";
|
||||
import { VersionMatchResult } from "./libtool-version.js";
|
||||
|
||||
/**
|
||||
* Response for the create reserve request to the wallet.
|
||||
@ -692,6 +693,7 @@ export interface ExchangeGlobalFees {
|
||||
|
||||
signature: string;
|
||||
}
|
||||
|
||||
const codecForExchangeAccount = (): Codec<ExchangeAccount> =>
|
||||
buildCodecForObject<ExchangeAccount>()
|
||||
.property("payto_uri", codecForString())
|
||||
@ -929,6 +931,110 @@ export interface ManualWithdrawalDetails {
|
||||
* Ways to pay the exchange.
|
||||
*/
|
||||
paytoUris: string[];
|
||||
|
||||
/**
|
||||
* If the exchange supports age-restricted coins it will return
|
||||
* the array of ages.
|
||||
*/
|
||||
ageRestrictionOptions?: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Selected denominations withn some extra info.
|
||||
*/
|
||||
export interface DenomSelectionState {
|
||||
totalCoinValue: AmountJson;
|
||||
totalWithdrawCost: AmountJson;
|
||||
selectedDenoms: {
|
||||
denomPubHash: string;
|
||||
count: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[];
|
||||
|
||||
/**
|
||||
* Selected denominations for withdraw.
|
||||
*/
|
||||
selectedDenoms: DenomSelectionState;
|
||||
|
||||
/**
|
||||
* Does the wallet know about an auditor for
|
||||
* the exchange that the reserve.
|
||||
*/
|
||||
isAudited: boolean;
|
||||
|
||||
/**
|
||||
* Did the user already accept the current terms of service for the exchange?
|
||||
*/
|
||||
termsOfServiceAccepted: boolean;
|
||||
|
||||
/**
|
||||
* The exchange is trusted directly.
|
||||
*/
|
||||
isTrusted: boolean;
|
||||
|
||||
/**
|
||||
* The earliest deposit expiration of the selected coins.
|
||||
*/
|
||||
earliestDepositExpiration: TalerProtocolTimestamp;
|
||||
|
||||
/**
|
||||
* Number of currently offered denominations.
|
||||
*/
|
||||
numOfferedDenoms: number;
|
||||
|
||||
/**
|
||||
* Public keys of trusted auditors for the currency we're withdrawing.
|
||||
*/
|
||||
trustedAuditorPubs: string[];
|
||||
|
||||
/**
|
||||
* 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[];
|
||||
}
|
||||
|
||||
export interface GetExchangeTosResult {
|
||||
@ -1142,24 +1248,6 @@ export const codecForForgetKnownBankAccounts =
|
||||
.property("payto", codecForString())
|
||||
.build("ForgetKnownBankAccountsRequest");
|
||||
|
||||
export interface GetExchangeWithdrawalInfo {
|
||||
exchangeBaseUrl: string;
|
||||
amount: AmountJson;
|
||||
tosAcceptedFormat?: string[];
|
||||
ageRestricted?: number;
|
||||
}
|
||||
|
||||
export const codecForGetExchangeWithdrawalInfo =
|
||||
(): Codec<GetExchangeWithdrawalInfo> =>
|
||||
buildCodecForObject<GetExchangeWithdrawalInfo>()
|
||||
.property("exchangeBaseUrl", codecForString())
|
||||
.property("amount", codecForAmountJson())
|
||||
.property(
|
||||
"tosAcceptedFormat",
|
||||
codecOptional(codecForList(codecForString())),
|
||||
)
|
||||
.build("GetExchangeWithdrawalInfo");
|
||||
|
||||
export interface AbortProposalRequest {
|
||||
proposalId: string;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import {
|
||||
DenominationInfo,
|
||||
GlobalFees,
|
||||
ExchangeGlobalFees,
|
||||
DenomSelectionState,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { RetryInfo, RetryTags } from "./util/retries.js";
|
||||
import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
|
||||
@ -430,8 +431,11 @@ export interface ExchangeDetailsRecord {
|
||||
|
||||
/**
|
||||
* Fees for exchange services
|
||||
*
|
||||
* FIXME: Put in separate object store!
|
||||
*/
|
||||
globalFees: ExchangeGlobalFees[];
|
||||
|
||||
/**
|
||||
* Signing keys we got from the exchange, can also contain
|
||||
* older signing keys that are not returned by /keys anymore.
|
||||
@ -1280,18 +1284,6 @@ export interface WalletBackupConfState {
|
||||
lastBackupNonce?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selected denominations withn some extra info.
|
||||
*/
|
||||
export interface DenomSelectionState {
|
||||
totalCoinValue: AmountJson;
|
||||
totalWithdrawCost: AmountJson;
|
||||
selectedDenoms: {
|
||||
denomPubHash: string;
|
||||
count: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
export const enum WithdrawalRecordType {
|
||||
BankManual = "bank-manual",
|
||||
BankIntegrated = "bank-integrated",
|
||||
|
@ -28,6 +28,7 @@ import {
|
||||
BackupWgType,
|
||||
codecForContractTerms,
|
||||
DenomKeyType,
|
||||
DenomSelectionState,
|
||||
j2s,
|
||||
Logger,
|
||||
PayCoinSelection,
|
||||
@ -43,7 +44,6 @@ import {
|
||||
CoinStatus,
|
||||
DenominationRecord,
|
||||
DenominationVerificationStatus,
|
||||
DenomSelectionState,
|
||||
OperationStatus,
|
||||
ProposalDownload,
|
||||
PurchaseStatus,
|
||||
|
@ -37,10 +37,12 @@ import {
|
||||
codecForWithdrawOperationStatusResponse,
|
||||
codecForWithdrawResponse,
|
||||
DenomKeyType,
|
||||
DenomSelectionState,
|
||||
Duration,
|
||||
durationFromSpec,
|
||||
encodeCrock,
|
||||
ExchangeListItem,
|
||||
ExchangeWithdrawalDetails,
|
||||
ExchangeWithdrawRequest,
|
||||
ForcedDenomSel,
|
||||
getRandomBytes,
|
||||
@ -67,9 +69,6 @@ import {
|
||||
CoinStatus,
|
||||
DenominationRecord,
|
||||
DenominationVerificationStatus,
|
||||
DenomSelectionState,
|
||||
ExchangeDetailsRecord,
|
||||
ExchangeRecord,
|
||||
PlanchetRecord,
|
||||
WalletStoresV1,
|
||||
WgInfo,
|
||||
@ -126,96 +125,6 @@ import {
|
||||
*/
|
||||
const logger = new Logger("operations/withdraw.ts");
|
||||
|
||||
/**
|
||||
* Information about what will happen when creating a reserve.
|
||||
*
|
||||
* Sent to the wallet frontend to be rendered and shown to the user.
|
||||
*/
|
||||
export interface ExchangeWithdrawDetails {
|
||||
/**
|
||||
* Exchange that the reserve will be created at.
|
||||
*
|
||||
* FIXME: Should be its own record.
|
||||
*/
|
||||
exchangeInfo: ExchangeRecord;
|
||||
|
||||
exchangeDetails: ExchangeDetailsRecord;
|
||||
|
||||
/**
|
||||
* Filtered wire info to send to the bank.
|
||||
*/
|
||||
exchangeWireAccounts: string[];
|
||||
|
||||
/**
|
||||
* Selected denominations for withdraw.
|
||||
*/
|
||||
selectedDenoms: DenomSelectionState;
|
||||
|
||||
/**
|
||||
* Does the wallet know about an auditor for
|
||||
* the exchange that the reserve.
|
||||
*/
|
||||
isAudited: boolean;
|
||||
|
||||
/**
|
||||
* Did the user already accept the current terms of service for the exchange?
|
||||
*/
|
||||
termsOfServiceAccepted: boolean;
|
||||
|
||||
/**
|
||||
* The exchange is trusted directly.
|
||||
*/
|
||||
isTrusted: boolean;
|
||||
|
||||
/**
|
||||
* The earliest deposit expiration of the selected coins.
|
||||
*/
|
||||
earliestDepositExpiration: TalerProtocolTimestamp;
|
||||
|
||||
/**
|
||||
* Number of currently offered denominations.
|
||||
*/
|
||||
numOfferedDenoms: number;
|
||||
|
||||
/**
|
||||
* Public keys of trusted auditors for the currency we're withdrawing.
|
||||
*/
|
||||
trustedAuditorPubs: string[];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a denom is withdrawable based on the expiration time,
|
||||
* revocation and offered state.
|
||||
@ -1280,7 +1189,7 @@ export async function getExchangeWithdrawalInfo(
|
||||
exchangeBaseUrl: string,
|
||||
instructedAmount: AmountJson,
|
||||
ageRestricted: number | undefined,
|
||||
): Promise<ExchangeWithdrawDetails> {
|
||||
): Promise<ExchangeWithdrawalDetails> {
|
||||
const { exchange, exchangeDetails } =
|
||||
await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl);
|
||||
await updateWithdrawalDenoms(ws, exchangeBaseUrl);
|
||||
@ -1378,10 +1287,14 @@ export async function getExchangeWithdrawalInfo(
|
||||
}
|
||||
}
|
||||
|
||||
const ret: ExchangeWithdrawDetails = {
|
||||
const paytoUris = exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri);
|
||||
if (!paytoUris) {
|
||||
throw Error("exchange is in invalid state");
|
||||
}
|
||||
|
||||
const ret: ExchangeWithdrawalDetails = {
|
||||
earliestDepositExpiration,
|
||||
exchangeInfo: exchange,
|
||||
exchangeDetails,
|
||||
exchangePaytoUris: paytoUris,
|
||||
exchangeWireAccounts,
|
||||
exchangeVersion: exchangeDetails.protocolVersion || "unknown",
|
||||
isAudited,
|
||||
|
@ -47,7 +47,6 @@ import {
|
||||
codecForForgetKnownBankAccounts,
|
||||
codecForGetContractTermsDetails,
|
||||
codecForGetExchangeTosRequest,
|
||||
codecForGetExchangeWithdrawalInfo,
|
||||
codecForGetFeeForDeposit,
|
||||
codecForGetWithdrawalDetailsForAmountRequest,
|
||||
codecForGetWithdrawalDetailsForUri,
|
||||
@ -112,7 +111,11 @@ import {
|
||||
importDb,
|
||||
WalletStoresV1,
|
||||
} from "./db.js";
|
||||
import { applyDevExperiment, maybeInitDevMode, setDevMode } from "./dev-experiments.js";
|
||||
import {
|
||||
applyDevExperiment,
|
||||
maybeInitDevMode,
|
||||
setDevMode,
|
||||
} from "./dev-experiments.js";
|
||||
import { getErrorDetailFromException, TalerError } from "./errors.js";
|
||||
import {
|
||||
ActiveLongpollInfo,
|
||||
@ -248,32 +251,6 @@ const builtinExchanges: string[] = ["https://exchange.demo.taler.net/"];
|
||||
|
||||
const logger = new Logger("wallet.ts");
|
||||
|
||||
async function getWithdrawalDetailsForAmount(
|
||||
ws: InternalWalletState,
|
||||
exchangeBaseUrl: string,
|
||||
amount: AmountJson,
|
||||
restrictAge: number | undefined,
|
||||
): Promise<ManualWithdrawalDetails> {
|
||||
const wi = await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
exchangeBaseUrl,
|
||||
amount,
|
||||
restrictAge,
|
||||
);
|
||||
const paytoUris = wi.exchangeDetails.wireInfo.accounts.map(
|
||||
(x) => x.payto_uri,
|
||||
);
|
||||
if (!paytoUris) {
|
||||
throw Error("exchange is in invalid state");
|
||||
}
|
||||
return {
|
||||
amountRaw: Amounts.stringify(amount),
|
||||
amountEffective: Amounts.stringify(wi.selectedDenoms.totalCoinValue),
|
||||
paytoUris,
|
||||
tosAccepted: wi.termsOfServiceAccepted,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the right handler for a pending operation without doing
|
||||
* any special error handling.
|
||||
@ -1038,16 +1015,6 @@ async function dispatchRequestInternal(
|
||||
const req = codecForGetWithdrawalDetailsForUri().decode(payload);
|
||||
return await getWithdrawalDetailsForUri(ws, req.talerWithdrawUri);
|
||||
}
|
||||
|
||||
case "getExchangeWithdrawalInfo": {
|
||||
const req = codecForGetExchangeWithdrawalInfo().decode(payload);
|
||||
return await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
req.exchangeBaseUrl,
|
||||
req.amount,
|
||||
req.ageRestricted,
|
||||
);
|
||||
}
|
||||
case "acceptManualWithdrawal": {
|
||||
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
|
||||
const res = await createManualWithdrawal(ws, {
|
||||
@ -1060,12 +1027,18 @@ async function dispatchRequestInternal(
|
||||
case "getWithdrawalDetailsForAmount": {
|
||||
const req =
|
||||
codecForGetWithdrawalDetailsForAmountRequest().decode(payload);
|
||||
return await getWithdrawalDetailsForAmount(
|
||||
const wi = await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
req.exchangeBaseUrl,
|
||||
Amounts.parseOrThrow(req.amount),
|
||||
req.restrictAge,
|
||||
);
|
||||
return {
|
||||
amountRaw: req.amount,
|
||||
amountEffective: Amounts.stringify(wi.selectedDenoms.totalCoinValue),
|
||||
paytoUris: wi.exchangePaytoUris,
|
||||
tosAccepted: wi.termsOfServiceAccepted,
|
||||
};
|
||||
}
|
||||
case "getBalances": {
|
||||
return await getBalances(ws);
|
||||
@ -1255,7 +1228,7 @@ async function dispatchRequestInternal(
|
||||
case "withdrawFakebank": {
|
||||
const req = codecForWithdrawFakebankRequest().decode(payload);
|
||||
const amount = Amounts.parseOrThrow(req.amount);
|
||||
const details = await getWithdrawalDetailsForAmount(
|
||||
const details = await getExchangeWithdrawalInfo(
|
||||
ws,
|
||||
req.exchange,
|
||||
amount,
|
||||
@ -1265,7 +1238,7 @@ async function dispatchRequestInternal(
|
||||
amount: amount,
|
||||
exchangeBaseUrl: req.exchange,
|
||||
});
|
||||
const paytoUri = details.paytoUris[0];
|
||||
const paytoUri = details.exchangePaytoUris[0];
|
||||
const pt = parsePaytoUri(paytoUri);
|
||||
if (!pt) {
|
||||
throw Error("failed to parse payto URI");
|
||||
|
@ -182,16 +182,15 @@ function exchangeSelectionState(
|
||||
* about the withdrawal
|
||||
*/
|
||||
const amountHook = useAsyncAsHook(async () => {
|
||||
const info = await api.getExchangeWithdrawalInfo({
|
||||
const info = await api.getWithdrawalDetailsForAmount({
|
||||
exchangeBaseUrl: currentExchange.exchangeBaseUrl,
|
||||
amount: chosenAmount,
|
||||
tosAcceptedFormat: ["text/xml"],
|
||||
ageRestricted,
|
||||
amount: Amounts.stringify(chosenAmount),
|
||||
restrictAge: ageRestricted,
|
||||
});
|
||||
|
||||
const withdrawAmount = {
|
||||
raw: Amounts.parseOrThrow(info.withdrawalAmountRaw),
|
||||
effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
|
||||
raw: Amounts.parseOrThrow(info.amountRaw),
|
||||
effective: Amounts.parseOrThrow(info.amountEffective),
|
||||
};
|
||||
|
||||
return {
|
||||
|
@ -22,14 +22,11 @@
|
||||
import {
|
||||
Amounts,
|
||||
ExchangeFullDetails,
|
||||
ExchangeListItem,
|
||||
GetExchangeTosResult,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core";
|
||||
import { expect } from "chai";
|
||||
import { mountHook } from "../../test-utils.js";
|
||||
import { useComponentStateFromURI } from "./state.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
|
||||
const exchanges: ExchangeFullDetails[] = [
|
||||
{
|
||||
@ -162,20 +159,11 @@ describe("Withdraw CTA states", () => {
|
||||
},
|
||||
{
|
||||
listExchanges: async () => ({ exchanges }),
|
||||
getWithdrawalDetailsForUri: async ({
|
||||
talerWithdrawUri,
|
||||
}: any): Promise<ExchangeWithdrawDetails> =>
|
||||
({
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
||||
} as Partial<ExchangeWithdrawDetails> as ExchangeWithdrawDetails),
|
||||
getExchangeWithdrawalInfo:
|
||||
async (): Promise<ExchangeWithdrawDetails> =>
|
||||
({
|
||||
withdrawalAmountRaw: "ARS:2",
|
||||
withdrawalAmountEffective: "ARS:2",
|
||||
} as any),
|
||||
}),
|
||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
||||
contentType: "text",
|
||||
content: "just accept",
|
||||
@ -255,19 +243,12 @@ describe("Withdraw CTA states", () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
listExchanges: async () => listExchangesResponse,
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) =>
|
||||
({
|
||||
listExchanges: async () => ({ exchanges }),
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
||||
} as Partial<ExchangeWithdrawDetails> as ExchangeWithdrawDetails),
|
||||
getExchangeWithdrawalInfo:
|
||||
async (): Promise<ExchangeWithdrawDetails> =>
|
||||
({
|
||||
withdrawalAmountRaw: "ARS:2",
|
||||
withdrawalAmountEffective: "ARS:2",
|
||||
} as any),
|
||||
}),
|
||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
||||
contentType: "text",
|
||||
content: "just accept",
|
||||
|
@ -51,8 +51,8 @@ import {
|
||||
ExchangesListResponse,
|
||||
ForgetKnownBankAccountsRequest,
|
||||
GetExchangeTosResult,
|
||||
GetExchangeWithdrawalInfo,
|
||||
GetFeeForDepositRequest,
|
||||
GetWithdrawalDetailsForAmountRequest,
|
||||
GetWithdrawalDetailsForUriRequest,
|
||||
InitiatePeerPullPaymentRequest,
|
||||
InitiatePeerPullPaymentResponse,
|
||||
@ -60,6 +60,7 @@ import {
|
||||
InitiatePeerPushPaymentResponse,
|
||||
KnownBankAccounts,
|
||||
Logger,
|
||||
ManualWithdrawalDetails,
|
||||
NotificationType,
|
||||
PaytoUri,
|
||||
PrepareDepositRequest,
|
||||
@ -81,7 +82,6 @@ import {
|
||||
import {
|
||||
AddBackupProviderRequest,
|
||||
BackupInfo,
|
||||
ExchangeWithdrawDetails,
|
||||
PendingOperationsResponse,
|
||||
RemoveBackupProviderRequest,
|
||||
TalerError,
|
||||
@ -459,14 +459,12 @@ export function getWithdrawalDetailsForUri(
|
||||
return callBackend("getWithdrawalDetailsForUri", req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diagnostics information
|
||||
*/
|
||||
export function getExchangeWithdrawalInfo(
|
||||
req: GetExchangeWithdrawalInfo,
|
||||
): Promise<ExchangeWithdrawDetails> {
|
||||
return callBackend("getExchangeWithdrawalInfo", req);
|
||||
export function getWithdrawalDetailsForAmount(
|
||||
req: GetWithdrawalDetailsForAmountRequest,
|
||||
): Promise<ManualWithdrawalDetails> {
|
||||
return callBackend("getWithdrawalDetailsForAmount", req);
|
||||
}
|
||||
|
||||
export function getExchangeTos(
|
||||
exchangeBaseUrl: string,
|
||||
acceptedFormat: string[],
|
||||
|
Loading…
Reference in New Issue
Block a user