gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: fixes #8228


From: gnunet
Subject: [taler-wallet-core] branch master updated: fixes #8228
Date: Tue, 13 Feb 2024 16:10:15 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 1d86bb8e9 fixes #8228
1d86bb8e9 is described below

commit 1d86bb8e9c74f09fd7dbeb2f806d857c8b8b5ea8
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Feb 13 12:09:28 2024 -0300

    fixes #8228
---
 packages/taler-util/src/transactions-types.ts      |  13 +++
 .../src/operations/transactions.ts                 |  86 +++++++++++---
 .../src/wallet/History.stories.tsx                 |  16 ++-
 .../src/wallet/History.tsx                         | 128 ++++++++++-----------
 4 files changed, 153 insertions(+), 90 deletions(-)

diff --git a/packages/taler-util/src/transactions-types.ts 
b/packages/taler-util/src/transactions-types.ts
index a0bc2a89d..3460d2d87 100644
--- a/packages/taler-util/src/transactions-types.ts
+++ b/packages/taler-util/src/transactions-types.ts
@@ -48,18 +48,29 @@ import {
 } from "./codec.js";
 import {
   RefreshReason,
+  ScopeInfo,
   TalerErrorDetail,
   TransactionIdStr,
   TransactionStateFilter,
   WithdrawalExchangeAccountDetails,
+  codecForScopeInfo,
 } from "./wallet-types.js";
 
 export interface TransactionsRequest {
   /**
    * return only transactions in the given currency
+   * 
+   * it will be removed in next release
+   * 
+   * @deprecated use scopeInfo
    */
   currency?: string;
 
+  /**
+   * return only transactions in the given scopeInfo
+   */
+  scopeInfo?: ScopeInfo;
+
   /**
    * if present, results will be limited to transactions related to the given 
search string
    */
@@ -77,6 +88,7 @@ export interface TransactionsRequest {
    */
   includeRefreshes?: boolean;
 
+
   filterByState?: TransactionStateFilter;
 }
 
@@ -730,6 +742,7 @@ export const codecForWithdrawalTransactionByURIRequest =
 export const codecForTransactionsRequest = (): Codec<TransactionsRequest> =>
   buildCodecForObject<TransactionsRequest>()
     .property("currency", codecOptional(codecForString()))
+    .property("scopeInfo", codecOptional(codecForScopeInfo()))
     .property("search", codecOptional(codecForString()))
     .property(
       "sort",
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index 8fd7afae6..13eda7a92 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -28,6 +28,7 @@ import {
   PeerContractTerms,
   RefundInfoShort,
   RefundPaymentInfo,
+  ScopeType,
   stringifyPayPullUri,
   stringifyPayPushUri,
   TalerErrorCode,
@@ -155,11 +156,30 @@ const logger = new 
Logger("taler-wallet-core:transactions.ts");
 function shouldSkipCurrency(
   transactionsRequest: TransactionsRequest | undefined,
   currency: string,
+  exchangesInTransaction: string[],
 ): boolean {
-  if (!transactionsRequest?.currency) {
-    return false;
+  if (transactionsRequest?.scopeInfo) {
+    const sameCurrency = transactionsRequest.scopeInfo.currency.toLowerCase() 
=== currency.toLowerCase()
+    switch (transactionsRequest.scopeInfo.type) {
+      case ScopeType.Global: {
+        return !sameCurrency
+      }
+      case ScopeType.Exchange: {
+        const exchangeInvolveInTransaction = 
exchangesInTransaction.indexOf(transactionsRequest.scopeInfo.url) !== -1
+        return !sameCurrency || !exchangeInvolveInTransaction
+      }
+      case ScopeType.Auditor: {
+        // same currency and same auditor
+        throw Error("filering balance in auditor scope is not implemented")
+      }
+      default: assertUnreachable(transactionsRequest.scopeInfo)
+    }
   }
-  return transactionsRequest.currency.toLowerCase() !== currency.toLowerCase();
+  // FIXME: remove next release
+  if (transactionsRequest?.currency) {
+    return transactionsRequest.currency.toLowerCase() !== 
currency.toLowerCase();
+  }
+  return false;
 }
 
 function shouldSkipSearch(
@@ -539,7 +559,7 @@ function buildTransactionForPeerPullCredit(
     const silentWithdrawalErrorForInvoice =
       wsrOrt?.lastError &&
       wsrOrt.lastError.code ===
-        TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE &&
+      TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE &&
       Object.values(wsrOrt.lastError.errorsPerCoin ?? {}).every((e) => {
         return (
           e.code === TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR &&
@@ -569,10 +589,10 @@ function buildTransactionForPeerPullCredit(
       kycUrl: pullCredit.kycUrl,
       ...(wsrOrt?.lastError
         ? {
-            error: silentWithdrawalErrorForInvoice
-              ? undefined
-              : wsrOrt.lastError,
-          }
+          error: silentWithdrawalErrorForInvoice
+            ? undefined
+            : wsrOrt.lastError,
+        }
         : {}),
     };
   }
@@ -1052,8 +1072,8 @@ export async function getTransactions(
     .runReadOnly(async (tx) => {
       await iterRecordsForPeerPushDebit(tx, filter, async (pi) => {
         const amount = Amounts.parseOrThrow(pi.amount);
-
-        if (shouldSkipCurrency(transactionsRequest, amount.currency)) {
+        const exchangesInTx = [pi.exchangeBaseUrl]
+        if (shouldSkipCurrency(transactionsRequest, amount.currency, 
exchangesInTx)) {
           return;
         }
         if (shouldSkipSearch(transactionsRequest, [])) {
@@ -1068,7 +1088,8 @@ export async function getTransactions(
 
       await iterRecordsForPeerPullDebit(tx, filter, async (pi) => {
         const amount = Amounts.parseOrThrow(pi.amount);
-        if (shouldSkipCurrency(transactionsRequest, amount.currency)) {
+        const exchangesInTx = [pi.exchangeBaseUrl]
+        if (shouldSkipCurrency(transactionsRequest, amount.currency, 
exchangesInTx)) {
           return;
         }
         if (shouldSkipSearch(transactionsRequest, [])) {
@@ -1102,7 +1123,8 @@ export async function getTransactions(
           // Legacy transaction
           return;
         }
-        if (shouldSkipCurrency(transactionsRequest, pi.currency)) {
+        const exchangesInTx = [pi.exchangeBaseUrl]
+        if (shouldSkipCurrency(transactionsRequest, pi.currency, 
exchangesInTx)) {
           return;
         }
         if (shouldSkipSearch(transactionsRequest, [])) {
@@ -1140,7 +1162,8 @@ export async function getTransactions(
 
       await iterRecordsForPeerPullCredit(tx, filter, async (pi) => {
         const currency = Amounts.currencyOf(pi.amount);
-        if (shouldSkipCurrency(transactionsRequest, currency)) {
+        const exchangesInTx = [pi.exchangeBaseUrl]
+        if (shouldSkipCurrency(transactionsRequest, currency, exchangesInTx)) {
           return;
         }
         if (shouldSkipSearch(transactionsRequest, [])) {
@@ -1173,7 +1196,19 @@ export async function getTransactions(
 
       await iterRecordsForRefund(tx, filter, async (refundGroup) => {
         const currency = Amounts.currencyOf(refundGroup.amountRaw);
-        if (shouldSkipCurrency(transactionsRequest, currency)) {
+
+        const exchangesInTx: string[] = []
+        const p = await tx.purchases.get(refundGroup.proposalId)
+        if (!p || !p.payInfo) return; //refund with no payment
+
+        p.payInfo.payCoinSelection.coinPubs.forEach(async (cp) => {
+          const c = await tx.coins.get(cp)
+          if (c?.exchangeBaseUrl) {
+            exchangesInTx.push(c.exchangeBaseUrl)
+          }
+        })
+
+        if (shouldSkipCurrency(transactionsRequest, currency, exchangesInTx)) {
           return;
         }
         const contractData = await lookupMaybeContractData(
@@ -1184,7 +1219,8 @@ export async function getTransactions(
       });
 
       await iterRecordsForRefresh(tx, filter, async (rg) => {
-        if (shouldSkipCurrency(transactionsRequest, rg.currency)) {
+        const exchangesInTx = rg.infoPerExchange ? 
Object.keys(rg.infoPerExchange) : []
+        if (shouldSkipCurrency(transactionsRequest, rg.currency, 
exchangesInTx)) {
           return;
         }
         let required = false;
@@ -1204,10 +1240,12 @@ export async function getTransactions(
       });
 
       await iterRecordsForWithdrawal(tx, filter, async (wsr) => {
+        const exchangesInTx = [wsr.exchangeBaseUrl]
         if (
           shouldSkipCurrency(
             transactionsRequest,
             Amounts.currencyOf(wsr.rawWithdrawalAmount),
+            exchangesInTx,
           )
         ) {
           return;
@@ -1259,7 +1297,8 @@ export async function getTransactions(
 
       await iterRecordsForDeposit(tx, filter, async (dg) => {
         const amount = Amounts.parseOrThrow(dg.amount);
-        if (shouldSkipCurrency(transactionsRequest, amount.currency)) {
+        const exchangesInTx = dg.infoPerExchange ? 
Object.keys(dg.infoPerExchange) : []
+        if (shouldSkipCurrency(transactionsRequest, amount.currency, 
exchangesInTx)) {
           return;
         }
         const opId = TaskIdentifiers.forDeposit(dg);
@@ -1276,7 +1315,16 @@ export async function getTransactions(
         if (!purchase.payInfo) {
           return;
         }
-        if (shouldSkipCurrency(transactionsRequest, download.currency)) {
+
+        const exchangesInTx: string[] = []
+        purchase.payInfo.payCoinSelection.coinPubs.forEach(async (cp) => {
+          const c = await tx.coins.get(cp)
+          if (c?.exchangeBaseUrl) {
+            exchangesInTx.push(c.exchangeBaseUrl)
+          }
+        })
+
+        if (shouldSkipCurrency(transactionsRequest, download.currency, 
exchangesInTx)) {
           return;
         }
         const contractTermsRecord = await tx.contractTerms.get(
@@ -1316,11 +1364,13 @@ export async function getTransactions(
         );
       });
 
+      //FIXME: remove rewards
       await iterRecordsForReward(tx, filter, async (tipRecord) => {
         if (
           shouldSkipCurrency(
             transactionsRequest,
             Amounts.parseOrThrow(tipRecord.rewardAmountRaw).currency,
+            [tipRecord.exchangeBaseUrl],
           )
         ) {
           return;
@@ -1332,6 +1382,8 @@ export async function getTransactions(
         const retryRecord = await tx.operationRetries.get(opId);
         transactions.push(buildTransactionForTip(tipRecord, retryRecord));
       });
+      //ends REMOVE REWARDS
+
     });
 
   // One-off checks, because of a bug where the wallet previously
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index cc87cb992..c28e4188f 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -162,11 +162,6 @@ const exampleData = {
   } as TransactionPeerPullDebit,
 };
 
-export const NoBalance = tests.createExample(TestedComponent, {
-  transactions: [],
-  balances: [],
-});
-
 export const SomeBalanceWithNoTransactions = tests.createExample(
   TestedComponent,
   {
@@ -186,6 +181,7 @@ export const SomeBalanceWithNoTransactions = 
tests.createExample(
         },
       },
     ],
+    balanceIndex: 0,
   },
 );
 
@@ -206,6 +202,8 @@ export const OneSimpleTransaction = 
tests.createExample(TestedComponent, {
       },
     },
   ],
+  balanceIndex: 0,
+
 });
 
 export const TwoTransactionsAndZeroBalance = tests.createExample(
@@ -227,6 +225,7 @@ export const TwoTransactionsAndZeroBalance = 
tests.createExample(
         },
       },
     ],
+    balanceIndex: 0,
   },
 );
 
@@ -254,6 +253,7 @@ export const OneTransactionPending = 
tests.createExample(TestedComponent, {
       },
     },
   ],
+  balanceIndex: 0,
 });
 
 export const SomeTransactions = tests.createExample(TestedComponent, {
@@ -288,6 +288,7 @@ export const SomeTransactions = 
tests.createExample(TestedComponent, {
       },
     },
   ],
+  balanceIndex: 0,
 });
 
 export const SomeTransactionsInDifferentStates = tests.createExample(
@@ -381,6 +382,7 @@ export const SomeTransactionsInDifferentStates = 
tests.createExample(
         },
       },
     ],
+    balanceIndex: 0,
   },
 );
 
@@ -424,6 +426,7 @@ export const SomeTransactionsWithTwoCurrencies = 
tests.createExample(
         },
       },
     ],
+    balanceIndex: 0,
   },
 );
 
@@ -496,6 +499,7 @@ export const FiveOfficialCurrencies = 
tests.createExample(TestedComponent, {
       },
     },
   ],
+  balanceIndex: 0,
 });
 
 export const FiveOfficialCurrenciesWithHighValue = tests.createExample(
@@ -569,6 +573,7 @@ export const FiveOfficialCurrenciesWithHighValue = 
tests.createExample(
         },
       },
     ],
+    balanceIndex: 0,
   },
 );
 
@@ -594,4 +599,5 @@ export const PeerToPeer = 
tests.createExample(TestedComponent, {
       },
     },
   ],
+  balanceIndex: 0,
 });
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 41b03424c..1cf7021d5 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -18,6 +18,7 @@ import {
   AbsoluteTime,
   Amounts,
   NotificationType,
+  ScopeInfo,
   ScopeType,
   Transaction,
   WalletBalance,
@@ -57,10 +58,16 @@ export function HistoryPage({
 }: Props): VNode {
   const { i18n } = useTranslationContext();
   const api = useBackendContext();
-  const state = useAsyncAsHook(async () => ({
-    b: await api.wallet.call(WalletApiOperation.GetBalances, {}),
-    tx: await api.wallet.call(WalletApiOperation.GetTransactions, {}),
-  }));
+  const [balanceIndex, setBalanceIndex] = useState<number>(0);
+
+  const state = useAsyncAsHook(async () => {
+    const b = await api.wallet.call(WalletApiOperation.GetBalances, {})
+    const balance = b.balances.length > 0 ? b.balances[balanceIndex] : 
undefined
+    const tx = await api.wallet.call(WalletApiOperation.GetTransactions, {
+      scopeInfo: balance?.scopeInfo
+    })
+    return { b, tx }
+  }, [balanceIndex]);
 
   useEffect(() => {
     return api.listener.onUpdateNotification(
@@ -68,6 +75,7 @@ export function HistoryPage({
       state?.retry,
     );
   });
+  const { pushAlertOnError } = useAlertContext();
 
   if (!state) {
     return <Loading />;
@@ -84,10 +92,20 @@ export function HistoryPage({
     );
   }
 
+  if (!state.response.b.balances.length) {
+    return (
+      <NoBalanceHelp
+        goToWalletManualWithdraw={{
+          onClick: pushAlertOnError(goToWalletManualWithdraw),
+        }}
+      />
+    );
+  }
   return (
     <HistoryView
+      balanceIndex={balanceIndex}
+      changeBalanceIndex={b => setBalanceIndex(b)}
       balances={state.response.b.balances}
-      defaultCurrency={currency}
       goToWalletManualWithdraw={goToWalletManualWithdraw}
       goToWalletDeposit={goToWalletDeposit}
       transactions={[...state.response.tx.transactions].reverse()}
@@ -95,66 +113,49 @@ export function HistoryPage({
   );
 }
 
-const term = 1000 * 60 * 60 * 24;
-function normalizeToDay(x: number): number {
-  return Math.round(x / term) * term;
-}
-
 export function HistoryView({
-  defaultCurrency,
-  transactions,
   balances,
+  balanceIndex,
+  changeBalanceIndex,
+  transactions,
   goToWalletManualWithdraw,
   goToWalletDeposit,
 }: {
+  balanceIndex: number,
+  changeBalanceIndex: (s: number) => void;
   goToWalletDeposit: (currency: string) => Promise<void>;
   goToWalletManualWithdraw: (currency?: string) => Promise<void>;
-  defaultCurrency?: string;
   transactions: Transaction[];
   balances: WalletBalance[];
 }): VNode {
   const { i18n } = useTranslationContext();
-  const { pushAlertOnError } = useAlertContext();
 
-  const transactionByCurrency = transactions.reduce((prev, cur) => {
-    const c = Amounts.parseOrThrow(cur.amountEffective).currency;
-    if (!prev[c]) {
-      prev[c] = [];
-    }
-    prev[c].push(cur);
-    return prev;
-  }, {} as Record<string, Transaction[]>);
+  // const currencies = balances
+  //   .filter((b) => {
+  //     const av = Amounts.parseOrThrow(b.available);
+  //     return (
+  //       Amounts.isNonZero(av) ||
+  //       (transactionByCurrency[av.currency] &&
+  //         transactionByCurrency[av.currency].length > 0)
+  //     );
+  //   });
 
-  const currencies = balances
-    .filter((b) => {
-      const av = Amounts.parseOrThrow(b.available);
-      return (
-        Amounts.isNonZero(av) ||
-        (transactionByCurrency[av.currency] &&
-          transactionByCurrency[av.currency].length > 0)
-      );
-    });
+  // const defaultCurrencyIndex = balances.findIndex(
+  //   (c) => c.scopeInfo.currency === defaultCurrency,
+  // );
+  // const [currencyIndex, setCurrencyIndex] = useState(
+  //   defaultCurrencyIndex === -1 ? 0 : defaultCurrencyIndex,
+  // );
+  // const selectedCurrency =
+  //   balances.length > 0 ? balances[currencyIndex] : undefined;
+  const balance = balances[balanceIndex];
 
-  const defaultCurrencyIndex = currencies.findIndex(
-    (c) => c.scopeInfo.currency === defaultCurrency,
-  );
-  const [currencyIndex, setCurrencyIndex] = useState(
-    defaultCurrencyIndex === -1 ? 0 : defaultCurrencyIndex,
-  );
-  const selectedCurrency =
-    currencies.length > 0 ? currencies[currencyIndex] : undefined;
-
-  const currencyAmount = balances[currencyIndex]
-    ? Amounts.jsonifyAmount(balances[currencyIndex].available)
+  const available = balance
+    ? Amounts.jsonifyAmount(balance.available)
     : undefined;
 
-  const ts =
-    selectedCurrency === undefined
-      ? []
-      : transactionByCurrency[selectedCurrency.scopeInfo.currency] ?? [];
-
   const datesWithTransaction: string[] = [];
-  const byDate = ts.reduce((rv, x) => {
+  const byDate = transactions.reduce((rv, x) => {
     const startDay =
       x.timestamp.t_s === "never" ? 0 : startOfDay(x.timestamp.t_s * 
1000).getTime();
     if (startDay) {
@@ -168,15 +169,6 @@ export function HistoryView({
     return rv;
   }, {} as { [x: string]: Transaction[] });
 
-  if (balances.length === 0 || !selectedCurrency) {
-    return (
-      <NoBalanceHelp
-        goToWalletManualWithdraw={{
-          onClick: pushAlertOnError(goToWalletManualWithdraw),
-        }}
-      />
-    );
-  }
   return (
     <Fragment>
       <section>
@@ -194,9 +186,9 @@ export function HistoryView({
               display: "flex",
             }}
           >
-            {currencies.length === 1 ? (
+            {balances.length === 1 ? (
               <CenteredText style={{ fontSize: "x-large", margin: 8 }}>
-                {selectedCurrency}
+                {balance.scopeInfo.currency}
               </CenteredText>
             ) : (
               <NiceSelect style={{ flexDirection: "column" }}>
@@ -204,12 +196,12 @@ export function HistoryView({
                   style={{
                     fontSize: "x-large",
                   }}
-                  value={currencyIndex}
+                  value={balanceIndex}
                   onChange={(e) => {
-                    setCurrencyIndex(Number(e.currentTarget.value));
+                    changeBalanceIndex(Number.parseInt(e.currentTarget.value, 
10));
                   }}
                 >
-                  {currencies.map((entry, index) => {
+                  {balances.map((entry, index) => {
                     return (
                       <option value={index} key={entry.scopeInfo.currency}>
                         {entry.scopeInfo.currency}
@@ -218,11 +210,11 @@ export function HistoryView({
                   })}
                 </select>
                 <div style={{ fontSize: "small", color: "grey" }}>
-                  {selectedCurrency.scopeInfo.type === ScopeType.Exchange || 
selectedCurrency.scopeInfo.type === ScopeType.Auditor ? 
selectedCurrency.scopeInfo.url : undefined}
+                  {balance.scopeInfo.type === ScopeType.Exchange || 
balance.scopeInfo.type === ScopeType.Auditor ? balance.scopeInfo.url : 
undefined}
                 </div>
               </NiceSelect>
             )}
-            {currencyAmount && (
+            {available && (
               <CenteredBoldText
                 style={{
                   display: "inline-block",
@@ -230,7 +222,7 @@ export function HistoryView({
                   margin: 8,
                 }}
               >
-                {Amounts.stringifyValue(currencyAmount, 2)}
+                {Amounts.stringifyValue(available, 2)}
               </CenteredBoldText>
             )}
           </div>
@@ -239,17 +231,17 @@ export function HistoryView({
               tooltip="Transfer money to the wallet"
               startIcon={DownloadIcon}
               variant="contained"
-              onClick={() => 
goToWalletManualWithdraw(selectedCurrency.scopeInfo.currency)}
+              onClick={() => 
goToWalletManualWithdraw(balance.scopeInfo.currency)}
             >
               <i18n.Translate>Add</i18n.Translate>
             </Button>
-            {currencyAmount && Amounts.isNonZero(currencyAmount) && (
+            {available && Amounts.isNonZero(available) && (
               <Button
                 tooltip="Transfer money from the wallet"
                 startIcon={UploadIcon}
                 variant="outlined"
                 color="primary"
-                onClick={() => 
goToWalletDeposit(selectedCurrency.scopeInfo.currency)}
+                onClick={() => goToWalletDeposit(balance.scopeInfo.currency)}
               >
                 <i18n.Translate>Send</i18n.Translate>
               </Button>

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]