diff options
author | Sebastian <sebasjm@gmail.com> | 2022-09-06 17:17:44 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-09-06 17:17:50 -0300 |
commit | 1e00724a0dcd0d65e6d786a1d8d7cdffc9fe2a85 (patch) | |
tree | 34eb327ac3370174cec4365ecc375309462d239b | |
parent | 49c9279c1e06a90757b2bd3e75b4887e71345d1d (diff) |
listExchangesDetailed to getExchangeDetailedInfo & ageRestriction taken from the denoms
22 files changed, 157 insertions, 120 deletions
diff --git a/packages/taler-util/src/transactionsTypes.ts b/packages/taler-util/src/transactionsTypes.ts index e4b1faf2e..a46f304d1 100644 --- a/packages/taler-util/src/transactionsTypes.ts +++ b/packages/taler-util/src/transactionsTypes.ts @@ -190,7 +190,6 @@ export interface TransactionWithdrawal extends TransactionCommon { export interface PeerInfoShort { expiration: TalerProtocolTimestamp | undefined; summary: string | undefined; - completed: boolean; } /** diff --git a/packages/taler-util/src/walletTypes.ts b/packages/taler-util/src/walletTypes.ts index 095266f22..7ca56b4ff 100644 --- a/packages/taler-util/src/walletTypes.ts +++ b/packages/taler-util/src/walletTypes.ts @@ -568,12 +568,12 @@ export interface DepositInfo { ageCommitmentProof?: AgeCommitmentProof; } -export interface ExchangesListRespose { +export interface ExchangesListResponse { exchanges: ExchangeListItem[]; } -export interface ExchangeDetailledListRespose { - exchanges: ExchangeFullDetailsListItem[]; +export interface ExchangeDetailedResponse { + exchange: ExchangeFullDetails; } export interface WalletCoreVersion { @@ -733,7 +733,7 @@ export interface DenominationInfo { stampExpireDeposit: TalerProtocolTimestamp; } -export interface ExchangeFullDetailsListItem { +export interface ExchangeFullDetails { exchangeBaseUrl: string; currency: string; paytoUris: string[]; @@ -771,9 +771,9 @@ const codecForExchangeTos = (): Codec<ExchangeTos> => .property("content", codecOptional(codecForString())) .build("ExchangeTos"); -export const codecForExchangeFullDetailsListItem = - (): Codec<ExchangeFullDetailsListItem> => - buildCodecForObject<ExchangeFullDetailsListItem>() +export const codecForExchangeFullDetails = + (): Codec<ExchangeFullDetails> => + buildCodecForObject<ExchangeFullDetails>() .property("currency", codecForString()) .property("exchangeBaseUrl", codecForString()) .property("paytoUris", codecForList(codecForString())) @@ -791,10 +791,10 @@ export const codecForExchangeListItem = (): Codec<ExchangeListItem> => .property("tos", codecForExchangeTos()) .build("ExchangeListItem"); -export const codecForExchangesListResponse = (): Codec<ExchangesListRespose> => - buildCodecForObject<ExchangesListRespose>() - .property("exchanges", codecForList(codecForExchangeFullDetailsListItem())) - .build("ExchangesListRespose"); +export const codecForExchangesListResponse = (): Codec<ExchangesListResponse> => + buildCodecForObject<ExchangesListResponse>() + .property("exchanges", codecForList(codecForExchangeListItem())) + .build("ExchangesListResponse"); export interface AcceptManualWithdrawalResult { /** @@ -965,6 +965,7 @@ export const codecForGetWithdrawalDetailsForAmountRequest = buildCodecForObject<GetWithdrawalDetailsForAmountRequest>() .property("exchangeBaseUrl", codecForString()) .property("amount", codecForString()) + .property("restrictAge", codecOptional(codecForNumber())) .build("GetWithdrawalDetailsForAmountRequest"); export interface AcceptExchangeTosRequest { @@ -1022,6 +1023,7 @@ export interface GetExchangeWithdrawalInfo { exchangeBaseUrl: string; amount: AmountJson; tosAcceptedFormat?: string[]; + ageRestricted?: number; } export const codecForGetExchangeWithdrawalInfo = diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index 9ca1ccb5a..7148999c5 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -82,10 +82,15 @@ export async function prepareTip( logger.trace("new tip, creating tip record"); await updateExchangeFromUrl(ws, tipPickupStatus.exchange_url); + + //FIXME: is this needed? withdrawDetails is not used + // * if the intention is to update the exchange information in the database + // maybe we can use another name. `get` seems like a pure-function const withdrawDetails = await getExchangeWithdrawalInfo( ws, tipPickupStatus.exchange_url, amount, + undefined ); const walletTipId = encodeCrock(getRandomBytes(32)); diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 11f47d8a0..956d565a6 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -161,7 +161,6 @@ export async function getTransactions( info: { expiration: pi.contractTerms.purse_expiration, summary: pi.contractTerms.summary, - completed: Amounts.isZero(amount), }, frozen: false, pending: !pi.purseCreated, @@ -199,7 +198,6 @@ export async function getTransactions( info: { expiration: pi.contractTerms.purse_expiration, summary: pi.contractTerms.summary, - completed: pi.paid }, timestamp: pi.timestampCreated, transactionId: makeEventId( @@ -234,7 +232,6 @@ export async function getTransactions( info: { expiration: wsr.wgInfo.contractTerms.purse_expiration, summary: wsr.wgInfo.contractTerms.summary, - completed: !!wsr.timestampFinish }, talerUri: constructPayPullUri({ exchangeBaseUrl: wsr.exchangeBaseUrl, @@ -259,7 +256,6 @@ export async function getTransactions( info: { expiration: wsr.wgInfo.contractTerms.purse_expiration, summary: wsr.wgInfo.contractTerms.summary, - completed: !!wsr.timestampFinish, }, pending: !wsr.timestampFinish, timestamp: wsr.timestampStart, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 2b981e117..b80745316 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -192,6 +192,13 @@ export interface ExchangeWithdrawDetails { * 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[], } /** @@ -242,7 +249,7 @@ export function selectWithdrawalDenominations( for (const d of denoms) { let count = 0; const cost = Amounts.add(d.value, d.feeWithdraw).amount; - for (;;) { + for (; ;) { if (Amounts.cmp(remaining, cost) < 0) { break; } @@ -903,8 +910,7 @@ export async function updateWithdrawalDenoms( denom.verificationStatus === DenominationVerificationStatus.Unverified ) { logger.trace( - `Validating denomination (${current + 1}/${ - denominations.length + `Validating denomination (${current + 1}/${denominations.length }) signature of ${denom.denomPubHash}`, ); let valid = false; @@ -1031,7 +1037,7 @@ async function queryReserve( if ( resp.status === 404 && result.talerErrorResponse.code === - TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN + TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN ) { ws.notify({ type: NotificationType.ReserveNotYetFound, @@ -1255,10 +1261,13 @@ async function processWithdrawGroupImpl( } } +const AGE_MASK_GROUPS = "8:10:12:14:16:18".split(":").map(n => parseInt(n, 10)) + export async function getExchangeWithdrawalInfo( ws: InternalWalletState, exchangeBaseUrl: string, instructedAmount: AmountJson, + ageRestricted: number | undefined, ): Promise<ExchangeWithdrawDetails> { const { exchange, exchangeDetails } = await ws.exchangeOps.updateExchangeFromUrl(ws, exchangeBaseUrl); @@ -1287,6 +1296,8 @@ export async function getExchangeWithdrawalInfo( exchange, ); + let hasDenomWithAgeRestriction = false + let earliestDepositExpiration: TalerProtocolTimestamp | undefined; for (let i = 0; i < selectedDenoms.selectedDenoms.length; i++) { const ds = selectedDenoms.selectedDenoms[i]; @@ -1310,6 +1321,7 @@ export async function getExchangeWithdrawalInfo( ) { earliestDepositExpiration = expireDeposit; } + hasDenomWithAgeRestriction = hasDenomWithAgeRestriction || denom.denomPub.age_mask > 0 } checkLogicInvariant(!!earliestDepositExpiration); @@ -1337,7 +1349,7 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, + `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, ); } } @@ -1370,6 +1382,9 @@ export async function getExchangeWithdrawalInfo( termsOfServiceAccepted: tosAccepted, withdrawalAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue), withdrawalAmountRaw: Amounts.stringify(instructedAmount), + // TODO: remove hardcoding, this should be calculated from the denominations info + // force enabled for testing + ageRestrictionOptions: hasDenomWithAgeRestriction ? AGE_MASK_GROUPS : undefined }; return ret; } diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts index 14c40a8db..665be80fb 100644 --- a/packages/taler-wallet-core/src/wallet-api-types.ts +++ b/packages/taler-wallet-core/src/wallet-api-types.ts @@ -46,7 +46,7 @@ import { CreateDepositGroupRequest, CreateDepositGroupResponse, DeleteTransactionRequest, - ExchangesListRespose, + ExchangesListResponse, ForceRefreshRequest, GetExchangeTosRequest, GetExchangeTosResult, @@ -227,7 +227,7 @@ export type WalletOperations = { }; [WalletApiOperation.ListExchanges]: { request: {}; - response: ExchangesListRespose; + response: ExchangesListResponse; }; [WalletApiOperation.AddExchange]: { request: AddExchangeRequest; diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index a7a39c5a9..a23bcb12a 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -72,8 +72,8 @@ import { Duration, durationFromSpec, durationMin, - ExchangeFullDetailsListItem, - ExchangesListRespose, + ExchangeFullDetails, + ExchangesListResponse, GetExchangeTosResult, j2s, KnownBankAccounts, @@ -232,8 +232,9 @@ async function getWithdrawalDetailsForAmount( ws: InternalWalletState, exchangeBaseUrl: string, amount: AmountJson, + restrictAge: number | undefined, ): Promise<ManualWithdrawalDetails> { - const wi = await getExchangeWithdrawalInfo(ws, exchangeBaseUrl, amount); + const wi = await getExchangeWithdrawalInfo(ws, exchangeBaseUrl, amount, restrictAge); const paytoUris = wi.exchangeDetails.wireInfo.accounts.map( (x) => x.payto_uri, ); @@ -568,7 +569,7 @@ async function listKnownBankAccounts( async function getExchanges( ws: InternalWalletState, -): Promise<ExchangesListRespose> { +): Promise<ExchangesListResponse> { const exchanges: ExchangeListItem[] = []; await ws.db .mktx((x) => ({ @@ -613,54 +614,56 @@ async function getExchanges( return { exchanges }; } -async function getExchangesDetailled( +async function getExchangeDetailedInfo( ws: InternalWalletState, -): Promise<ExchangesListRespose> { - const exchanges: ExchangeFullDetailsListItem[] = []; - await ws.db + exchangeBaseurl: string, +): Promise<ExchangeFullDetails> { + //TODO: should we use the forceUpdate parameter? + const exchange = await ws.db .mktx((x) => ({ exchanges: x.exchanges, exchangeDetails: x.exchangeDetails, denominations: x.denominations, })) .runReadOnly(async (tx) => { - const exchangeRecords = await tx.exchanges.iter().toArray(); - for (const r of exchangeRecords) { - const dp = r.detailsPointer; - if (!dp) { - continue; - } - const { currency } = dp; - const exchangeDetails = await getExchangeDetails(tx, r.baseUrl); - if (!exchangeDetails) { - continue; - } + const ex = await tx.exchanges.get(exchangeBaseurl) + const dp = ex?.detailsPointer; + if (!dp) { + return; + } + const { currency } = dp; + const exchangeDetails = await getExchangeDetails(tx, ex.baseUrl); + if (!exchangeDetails) { + return; + } - const denominations = await tx.denominations.indexes.byExchangeBaseUrl - .iter(r.baseUrl) - .toArray(); + const denominations = await tx.denominations.indexes.byExchangeBaseUrl + .iter(ex.baseUrl) + .toArray(); - if (!denominations) { - continue; - } + if (!denominations) { + return; + } - exchanges.push({ - exchangeBaseUrl: r.baseUrl, - currency, - tos: { - acceptedVersion: exchangeDetails.termsOfServiceAcceptedEtag, - currentVersion: exchangeDetails.termsOfServiceLastEtag, - contentType: exchangeDetails.termsOfServiceContentType, - content: exchangeDetails.termsOfServiceText, - }, - paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri), - auditors: exchangeDetails.auditors, - wireInfo: exchangeDetails.wireInfo, - denominations: denominations, - }); + return { + exchangeBaseUrl: ex.baseUrl, + currency, + tos: { + acceptedVersion: exchangeDetails.termsOfServiceAcceptedEtag, + currentVersion: exchangeDetails.termsOfServiceLastEtag, + contentType: exchangeDetails.termsOfServiceContentType, + content: exchangeDetails.termsOfServiceText, + }, + paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri), + auditors: exchangeDetails.auditors, + wireInfo: exchangeDetails.wireInfo, + denominations: denominations, } }); - return { exchanges }; + if (!exchange) { + throw Error(`exchange with base url "${exchangeBaseurl}" not found`) + } + return exchange; } async function setCoinSuspended( @@ -834,8 +837,9 @@ async function dispatchRequestInternal( case "listExchanges": { return await getExchanges(ws); } - case "listExchangesDetailled": { - return await getExchangesDetailled(ws); + case "getExchangeDetailedInfo": { + const req = codecForAddExchangeRequest().decode(payload); + return await getExchangeDetailedInfo(ws, req.exchangeBaseUrl); } case "listKnownBankAccounts": { const req = codecForListKnownBankAccounts().decode(payload); @@ -852,6 +856,7 @@ async function dispatchRequestInternal( ws, req.exchangeBaseUrl, req.amount, + req.ageRestricted, ); } case "acceptManualWithdrawal": { @@ -870,6 +875,7 @@ async function dispatchRequestInternal( ws, req.exchangeBaseUrl, Amounts.parseOrThrow(req.amount), + req.restrictAge ); } case "getBalances": { @@ -1067,6 +1073,7 @@ async function dispatchRequestInternal( ws, req.exchange, amount, + undefined ); const wres = await createManualWithdrawal(ws, { amount: amount, diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index bb0f0d1af..804d216eb 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -30,7 +30,7 @@ export function useComponentState( const [subject, setSubject] = useState(""); const [talerUri, setTalerUri] = useState("") - const hook = useAsyncAsHook(api.listExchangesDetailled); + const hook = useAsyncAsHook(api.listExchanges); const [exchangeIdx, setExchangeIdx] = useState("0") const [operationError, setOperationError] = useState<TalerErrorDetail | undefined>(undefined) diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index 58d3cfedf..015c9aaca 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -30,7 +30,7 @@ export function useComponentStateFromParams( const [ageRestricted, setAgeRestricted] = useState(0); - const exchangeHook = useAsyncAsHook(api.listExchangesDetailled); + const exchangeHook = useAsyncAsHook(api.listExchanges); const exchangeHookDep = !exchangeHook || exchangeHook.hasError || !exchangeHook.response @@ -65,6 +65,7 @@ export function useComponentStateFromParams( exchangeBaseUrl: exchange.exchangeBaseUrl, amount: chosenAmount, tosAcceptedFormat: ["text/xml"], + ageRestricted, }); const withdrawAmount = { @@ -72,7 +73,7 @@ export function useComponentStateFromParams( effective: Amounts.parseOrThrow(info.withdrawalAmountEffective), } - return { amount: withdrawAmount }; + return { amount: withdrawAmount, ageRestrictionOptions: info.ageRestrictionOptions }; }, [exchangeHookDep]); const [reviewing, setReviewing] = useState<boolean>(false); @@ -172,16 +173,16 @@ export function useComponentStateFromParams( termsState !== undefined && (termsState.status === "changed" || termsState.status === "new"); - const ageRestrictionOptions: Record<string, string> | undefined = "6:12:18" - .split(":") - .reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {}); + const ageRestrictionOptions = amountHook.response. + ageRestrictionOptions?. + reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {} as Record<string, string>) - if (ageRestrictionOptions) { + const ageRestrictionEnabled = ageRestrictionOptions !== undefined + if (ageRestrictionEnabled) { ageRestrictionOptions["0"] = "Not restricted"; } //TODO: calculate based on exchange info - const ageRestrictionEnabled = false; const ageRestriction = ageRestrictionEnabled ? { list: ageRestrictionOptions, value: String(ageRestricted), @@ -269,6 +270,7 @@ export function useComponentStateFromURI( exchangeBaseUrl: uriHookDep?.thisExchange, amount: Amounts.parseOrThrow(uriHookDep.amount), tosAcceptedFormat: ["text/xml"], + ageRestricted, }); const withdrawAmount = { @@ -276,7 +278,7 @@ export function useComponentStateFromURI( effective: Amounts.parseOrThrow(info.withdrawalAmountEffective), } - return { amount: withdrawAmount }; + return { amount: withdrawAmount, ageRestrictionOptions: info.ageRestrictionOptions }; }, [uriHookDep]); const [reviewing, setReviewing] = useState<boolean>(false); @@ -385,16 +387,16 @@ export function useComponentStateFromURI( termsState !== undefined && (termsState.status === "changed" || termsState.status === "new"); - const ageRestrictionOptions: Record<string, string> | undefined = "6:12:18" - .split(":") - .reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {}); + const ageRestrictionOptions = amountHook.response. + ageRestrictionOptions?. + reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {} as Record<string, string>) - if (ageRestrictionOptions) { + const ageRestrictionEnabled = ageRestrictionOptions !== undefined + if (ageRestrictionEnabled) { ageRestrictionOptions["0"] = "Not restricted"; } //TODO: calculate based on exchange info - const ageRestrictionEnabled = false; const ageRestriction = ageRestrictionEnabled ? { list: ageRestrictionOptions, value: String(ageRestricted), diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts index 6c9e0c3ba..ce964f7f7 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -21,7 +21,7 @@ import { Amounts, - ExchangeFullDetailsListItem, + ExchangeFullDetails, ExchangeListItem, GetExchangeTosResult, } from "@gnu-taler/taler-util"; @@ -30,7 +30,7 @@ import { expect } from "chai"; import { mountHook } from "../../test-utils.js"; import { useComponentStateFromURI } from "./state.js"; -const exchanges: ExchangeFullDetailsListItem[] = [ +const exchanges: ExchangeFullDetails[] = [ { currency: "ARS", exchangeBaseUrl: "http://exchange.demo.taler.net", diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx index b63bbacaf..fa1a606f7 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx @@ -171,7 +171,7 @@ export function SelectCurrency({ }): VNode { const { i18n } = useTranslationContext(); - const hook = useAsyncAsHook(wxApi.listExchangesDetailled); + const hook = useAsyncAsHook(wxApi.listExchanges); if (!hook) { return <Loading />; diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx index 8ba92a8f2..3406b04ef 100644 --- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx @@ -45,7 +45,7 @@ export function DeveloperPage(): VNode { const response = useAsyncAsHook(async () => { const op = await wxApi.getPendingOperations(); const c = await wxApi.dumpCoins(); - const ex = await wxApi.listExchangesDetailled(); + const ex = await wxApi.listExchanges(); return { operations: op.pendingOperations, coins: c.coins, diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx index 8ba5fb7e9..859a7f86b 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx @@ -36,7 +36,7 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode { { url: string; config: TalerConfigResponse } | undefined >(undefined); - const knownExchangesResponse = useAsyncAsHook(wxApi.listExchangesDetailled); + const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges); const knownExchanges = !knownExchangesResponse ? [] : knownExchangesResponse.hasError diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/example.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/example.ts index bdbd36596..3f37dda77 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/example.ts +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/example.ts @@ -15,7 +15,7 @@ */ import { - ExchangeFullDetailsListItem, + ExchangeFullDetails, ExchangeListItem, } from "@gnu-taler/taler-util"; @@ -24,7 +24,7 @@ import { * @author Sebastian Javier Marchano (sebasjm) */ -export const bitcoinExchanges: ExchangeFullDetailsListItem[] = [ +export const bitcoinExchanges: ExchangeFullDetails[] = [ { exchangeBaseUrl: "https://bitcoin1.ice.bfh.ch/", currency: "BITCOINBTC", @@ -11781,7 +11781,7 @@ export const bitcoinExchanges: ExchangeFullDetailsListItem[] = [ }, ] as any; -export const kudosExchanges: ExchangeFullDetailsListItem[] = [ +export const kudosExchanges: ExchangeFullDetails[] = [ { exchangeBaseUrl: "https://exchange1.demo.taler.net/", currency: "KUDOS", diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts index 0dec00b09..061c94ad7 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AbsoluteTime, AmountJson, ExchangeFullDetailsListItem } from "@gnu-taler/taler-util"; +import { AbsoluteTime, AmountJson, ExchangeFullDetails } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; import { HookError } from "../../hooks/useAsyncAsHook.js"; import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js"; @@ -52,7 +52,7 @@ export namespace State { export interface BaseInfo { exchanges: SelectFieldHandler; - selected: ExchangeFullDetailsListItem; + selected: ExchangeFullDetails; nextFeeUpdate: AbsoluteTime; error: undefined; } diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts index eda755e96..28d34578a 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts @@ -25,11 +25,21 @@ export function useComponentState( { onCancel, onSelection, currency }: Props, api: typeof wxApi, ): State { - const hook = useAsyncAsHook(api.listExchangesDetailled); - const initialValue = 0 const [value, setValue] = useState(String(initialValue)); + const hook = useAsyncAsHook(async () => { + const { exchanges } = await api.listExchanges() + + const selectedIdx = parseInt(value, 10) + const selectedExchange = exchanges.length == 0 ? undefined : exchanges[selectedIdx] + const selected = !selectedExchange ? undefined : await api.getExchangeDetailedInfo(selectedExchange.exchangeBaseUrl) + + const initialExchange = selectedIdx === initialValue ? undefined : exchanges[initialValue] + const original = !initialExchange ? undefined : await api.getExchangeDetailedInfo(initialExchange.exchangeBaseUrl) + return { exchanges, selected, original } + }); + if (!hook) { return { status: "loading", @@ -43,18 +53,16 @@ export function useComponentState( }; } - const exchanges = hook.response.exchanges; + const { exchanges, selected, original } = hook.response; - if (exchanges.length === 0) { + if (!selected) { + //!selected <=> exchanges.length === 0 return { status: "no-exchanges", error: undefined } } - const original = exchanges[initialValue]; - const selected = exchanges[Number(value)]; - let nextFeeUpdate = TalerProtocolTimestamp.never(); nextFeeUpdate = Object.values(selected.wireInfo.feesForType).reduce( @@ -97,7 +105,8 @@ export function useComponentState( const exchangeMap = exchanges.reduce((prev, cur, idx) => ({ ...prev, [cur.exchangeBaseUrl]: String(idx) }), {} as Record<string, string>) - if (original === selected) { + if (!original) { + // !original <=> selected == original return { status: "ready", exchanges: { diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/stories.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/stories.tsx index 094087517..cb4cc7c69 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/stories.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { ExchangeFullDetailsListItem, ExchangeListItem } from "@gnu-taler/taler-util"; +import { ExchangeFullDetails, ExchangeListItem } from "@gnu-taler/taler-util"; import { createExample } from "../../test-utils.js"; import { bitcoinExchanges, kudosExchanges } from "./example.js"; import { FeeDescription, FeeDescriptionPair, OperationMap } from "./index.js"; @@ -34,7 +34,7 @@ export default { }; function timelineForExchange( - ex: ExchangeFullDetailsListItem, + ex: ExchangeFullDetails, ): OperationMap<FeeDescription[]> { return { deposit: createDenominationTimeline( @@ -61,8 +61,8 @@ function timelineForExchange( } function timelinePairForExchange( - ex1: ExchangeFullDetailsListItem, - ex2: ExchangeFullDetailsListItem, + ex1: ExchangeFullDetails, + ex2: ExchangeFullDetails, ): OperationMap<FeeDescriptionPair[]> { const om1 = timelineForExchange(ex1); const om2 = timelineForExchange(ex2); diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx index 5a82c96ed..a292914fb 100644 --- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx @@ -50,7 +50,7 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode { >(undefined); const [error, setError] = useState<string | undefined>(undefined); - const state = useAsyncAsHook(wxApi.listExchangesDetailled); + const state = useAsyncAsHook(wxApi.listExchanges); useEffect(() => { return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => { state?.retry(); diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 36a356fba..4a520c3bb 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -49,7 +49,7 @@ export function SettingsPage(): VNode { const webex = platform.getWalletWebExVersion(); const exchangesHook = useAsyncAsHook(async () => { - const list = await wxApi.listExchangesDetailled(); + const list = await wxApi.listExchanges(); const version = await wxApi.getVersion(); return { exchanges: list.exchanges, version }; }); diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx index acb50642a..dc8f067a5 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx @@ -563,7 +563,7 @@ export const InvoiceCreditComplete = createExample(TestedComponent, { export const InvoiceCreditIncomplete = createExample(TestedComponent, { transaction: { ...exampleData.pull_credit, - info: { ...exampleData.pull_credit.info, completed: false }, + pending: true, }, }); @@ -581,9 +581,6 @@ export const TransferDebitComplete = createExample(TestedComponent, { export const TransferDebitIncomplete = createExample(TestedComponent, { transaction: { ...exampleData.push_debit, - info: { - ...exampleData.push_debit.info, - completed: false, - }, + pending: true, }, }); diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index 44543c2cd..c1f5861e8 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -167,6 +167,8 @@ export function TransactionView({ } } + const SHOWING_RETRY_THRESHOLD_SECS = 30; + const { i18n } = useTranslationContext(); function TransactionTemplate({ @@ -174,15 +176,16 @@ export function TransactionView({ }: { children: ComponentChildren; }): VNode { - const showSend = - (transaction.type === TransactionType.PeerPullCredit || - transaction.type === TransactionType.PeerPushDebit) && - !transaction.info.completed; + const showSend = false; + // (transaction.type === TransactionType.PeerPullCredit || + // transaction.type === TransactionType.PeerPushDebit) && + // !transaction.info.completed; const showRetry = transaction.error !== undefined || transaction.timestamp.t_s === "never" || (transaction.pending && - differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) > 10); + differenceInSeconds(new Date(), transaction.timestamp.t_s * 1000) > + SHOWING_RETRY_THRESHOLD_SECS); return ( <Fragment> @@ -624,7 +627,7 @@ export function TransactionView({ text={transaction.exchangeBaseUrl} kind="neutral" /> - {!transaction.info.completed && ( + {transaction.pending && ( <Part title={<i18n.Translate>URI</i18n.Translate>} text={<ShowQrWithCopy text={transaction.talerUri} />} @@ -710,7 +713,7 @@ export function TransactionView({ text={transaction.exchangeBaseUrl} kind="neutral" /> - {!transaction.info.completed && ( + {transaction.pending && ( <Part title={<i18n.Translate>URI</i18n.Translate>} text={<ShowQrWithCopy text={transaction.talerUri} />} diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts index 1b26ea214..b797179c3 100644 --- a/packages/taler-wallet-webextension/src/wxApi.ts +++ b/packages/taler-wallet-webextension/src/wxApi.ts @@ -42,7 +42,7 @@ import { CreateDepositGroupRequest, CreateDepositGroupResponse, DeleteTransactionRequest, - ExchangesListRespose, + ExchangesListResponse, GetExchangeTosResult, GetExchangeWithdrawalInfo, GetFeeForDepositRequest, @@ -67,7 +67,7 @@ import { WalletDiagnostics, WalletCoreVersion, WithdrawUriInfoResponse, - ExchangeDetailledListRespose, + ExchangeFullDetails, } from "@gnu-taler/taler-util"; import { AddBackupProviderRequest, @@ -253,12 +253,14 @@ export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> { }); } -export function listExchanges(): Promise<ExchangesListRespose> { +export function listExchanges(): Promise<ExchangesListResponse> { return callBackend("listExchanges", {}); } -export function listExchangesDetailled(): Promise<ExchangeDetailledListRespose> { - return callBackend("listExchangesDetailled", {}); +export function getExchangeDetailedInfo(exchangeBaseUrl: string): Promise<ExchangeFullDetails> { + return callBackend("getExchangeDetailedInfo", { + exchangeBaseUrl + }); } export function getVersion(): Promise<WalletCoreVersion> { |