From fef7985be3ac1440d02f9ddc9f5aa141586a5259 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 5 Dec 2023 18:51:58 +0100 Subject: wallet-core: make conversion more robust against errors --- packages/taler-util/src/wallet-types.ts | 15 +++ .../taler-wallet-core/src/operations/withdraw.ts | 123 +++++++++++++-------- 2 files changed, 92 insertions(+), 46 deletions(-) (limited to 'packages') diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index 8e72a4949..f19a0dd10 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -2782,6 +2782,16 @@ export interface WithdrawalExchangeAccountDetails { */ paytoUri: string; + /** + * Status that indicates whether the account can be used + * by the user to send funds for a withdrawal. + * + * ok: account should be shown to the user + * error: account should not be shown to the user, UIs might render the error (in conversionError), + * especially in dev mode. + */ + status: "ok" | "error"; + /** * Transfer amount. Might be in a different currency than the requested * amount for withdrawal. @@ -2804,4 +2814,9 @@ export interface WithdrawalExchangeAccountDetails { * exchange. */ creditRestrictions?: AccountRestriction[]; + + /** + * Error that happened when attempting to request the conversion rate. + */ + conversionError?: TalerErrorDetail; } diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 63c811e60..b9ba3058f 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -35,6 +35,7 @@ import { Duration, ExchangeBatchWithdrawRequest, ExchangeListItem, + ExchangeWireAccount, ExchangeWithdrawBatchResponse, ExchangeWithdrawRequest, ExchangeWithdrawResponse, @@ -2584,6 +2585,76 @@ export async function acceptWithdrawalFromUri( }; } +async function fetchAccount( + ws: InternalWalletState, + instructedAmount: AmountJson, + acct: ExchangeWireAccount, + reservePub?: string, +): Promise { + let paytoUri: string; + let transferAmount: AmountString | undefined = undefined; + let currencySpecification: CurrencySpecification | undefined = undefined; + if (acct.conversion_url != null) { + const reqUrl = new URL("cashin-rate", acct.conversion_url); + reqUrl.searchParams.set( + "amount_credit", + Amounts.stringify(instructedAmount), + ); + const httpResp = await ws.http.fetch(reqUrl.href); + const respOrErr = await readSuccessResponseJsonOrErrorCode( + httpResp, + codecForCashinConversionResponse(), + ); + if (respOrErr.isError) { + return { + status: "error", + paytoUri: acct.payto_uri, + conversionError: respOrErr.talerErrorResponse, + }; + } + const resp = respOrErr.response; + paytoUri = acct.payto_uri; + transferAmount = resp.amount_debit; + const configUrl = new URL("config", acct.conversion_url); + const configResp = await ws.http.fetch(configUrl.href); + const configRespOrError = await readSuccessResponseJsonOrErrorCode( + configResp, + codecForConversionBankConfig(), + ); + if (configRespOrError.isError) { + return { + status: "error", + paytoUri: acct.payto_uri, + conversionError: configRespOrError.talerErrorResponse, + }; + } + const configParsed = configRespOrError.response; + currencySpecification = configParsed.fiat_currency_specification; + } else { + paytoUri = acct.payto_uri; + transferAmount = Amounts.stringify(instructedAmount); + } + paytoUri = addPaytoQueryParams(paytoUri, { + amount: Amounts.stringify(transferAmount), + }); + if (reservePub != null) { + paytoUri = addPaytoQueryParams(paytoUri, { + message: `Taler Withdrawal ${reservePub}`, + }); + } + const acctInfo: WithdrawalExchangeAccountDetails = { + status: "ok", + paytoUri, + transferAmount, + currencySpecification, + creditRestrictions: acct.credit_restrictions, + }; + if (transferAmount != null) { + acctInfo.transferAmount = transferAmount; + } + return acctInfo; +} + /** * Gather information about bank accounts that can be used for * withdrawals. This includes accounts that are in a different @@ -2600,52 +2671,12 @@ async function fetchWithdrawalAccountInfo( const { exchangeDetails, instructedAmount } = req; const withdrawalAccounts: WithdrawalExchangeAccountDetails[] = []; for (let acct of exchangeDetails.wireInfo.accounts) { - let paytoUri: string; - let transferAmount: AmountString | undefined = undefined; - let currencySpecification: CurrencySpecification | undefined = undefined; - if (acct.conversion_url != null) { - const reqUrl = new URL("cashin-rate", acct.conversion_url); - reqUrl.searchParams.set( - "amount_credit", - Amounts.stringify(instructedAmount), - ); - const httpResp = await ws.http.fetch(reqUrl.href); - const resp = await readSuccessResponseJsonOrThrow( - httpResp, - codecForCashinConversionResponse(), - ); - paytoUri = acct.payto_uri; - transferAmount = resp.amount_debit; - const configUrl = new URL("config", acct.conversion_url); - const configResp = await ws.http.fetch(configUrl.href); - const configParsed = await readSuccessResponseJsonOrThrow( - configResp, - codecForConversionBankConfig(), - ); - currencySpecification = configParsed.fiat_currency_specification; - if (req.reservePub) { - } - } else { - paytoUri = acct.payto_uri; - transferAmount = Amounts.stringify(instructedAmount); - } - paytoUri = addPaytoQueryParams(paytoUri, { - amount: Amounts.stringify(transferAmount), - }); - if (req.reservePub != null) { - paytoUri = addPaytoQueryParams(paytoUri, { - message: `Taler Withdrawal ${req.reservePub}`, - }); - } - const acctInfo: WithdrawalExchangeAccountDetails = { - paytoUri, - transferAmount, - currencySpecification, - creditRestrictions: acct.credit_restrictions, - }; - if (transferAmount != null) { - acctInfo.transferAmount = transferAmount; - } + const acctInfo = await fetchAccount( + ws, + req.instructedAmount, + acct, + req.reservePub, + ); withdrawalAccounts.push(acctInfo); } return withdrawalAccounts; -- cgit v1.2.3