gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: finish refresh correctly, di


From: gnunet
Subject: [taler-wallet-core] branch master updated: finish refresh correctly, display fees correctly
Date: Mon, 16 Dec 2019 21:11:02 +0100

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

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

The following commit(s) were added to refs/heads/master by this push:
     new fb6508de finish refresh correctly, display fees correctly
fb6508de is described below

commit fb6508de9d71600dbca59cb0e6a4c77e4f3f3ee5
Author: Florian Dold <address@hidden>
AuthorDate: Mon Dec 16 21:10:57 2019 +0100

    finish refresh correctly, display fees correctly
---
 src/headless/taler-wallet-cli.ts |  30 ++++++--
 src/operations/history.ts        |  69 ++++++++++++-----
 src/operations/pending.ts        |   2 +
 src/operations/refresh.ts        |  14 +++-
 src/operations/reserves.ts       | 161 +++++++++++++++++++++------------------
 src/types/history.ts             |  10 +++
 src/types/notifications.ts       |   7 +-
 src/types/pending.ts             |   2 +
 8 files changed, 189 insertions(+), 106 deletions(-)

diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts
index bc83bac2..610990ae 100644
--- a/src/headless/taler-wallet-cli.ts
+++ b/src/headless/taler-wallet-cli.ts
@@ -1,17 +1,17 @@
 /*
- This file is part of TALER
- (C) 2019 GNUnet e.V.
+ This file is part of GNU Taler
+ (C) 2019 Taler Systems S.A.
 
- TALER is free software; you can redistribute it and/or modify it under the
+ GNU Taler is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.
 
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
 import os = require("os");
@@ -167,7 +167,10 @@ walletCli
   });
 
 walletCli
-  .subcommand("", "history", { help: "Show wallet event history." })
+  .subcommand("history", "history", { help: "Show wallet event history." })
+  .flag("json", ["--json"], {
+    default: false,
+  })
   .maybeOption("from", ["--from"], clk.STRING)
   .maybeOption("to", ["--to"], clk.STRING)
   .maybeOption("limit", ["--limit"], clk.STRING)
@@ -175,7 +178,17 @@ walletCli
   .action(async args => {
     await withWallet(args, async wallet => {
       const history = await wallet.getHistory();
-      console.log(JSON.stringify(history, undefined, 2));
+      if (args.history.json) {
+        console.log(JSON.stringify(history, undefined, 2));
+      } else {
+        for (const h of history.history) {
+          console.log(
+            `event at ${new Date(h.timestamp.t_ms).toISOString()} with type 
${h.type}:`,
+          );
+          console.log(JSON.stringify(h, undefined, 2));
+          console.log();
+        }
+      }
     });
   });
 
@@ -231,7 +244,8 @@ walletCli
         case TalerUriType.TalerWithdraw:
           {
             const withdrawInfo = await wallet.getWithdrawDetailsForUri(uri);
-            const selectedExchange = 
withdrawInfo.bankWithdrawDetails.suggestedExchange;
+            const selectedExchange =
+              withdrawInfo.bankWithdrawDetails.suggestedExchange;
             if (!selectedExchange) {
               console.error("no suggested exchange!");
               process.exit(1);
diff --git a/src/operations/history.ts b/src/operations/history.ts
index eec398f3..bb57a9c6 100644
--- a/src/operations/history.ts
+++ b/src/operations/history.ts
@@ -61,7 +61,6 @@ function getOrderShortInfo(
   };
 }
 
-
 async function collectProposalHistory(
   tx: TransactionHandle,
   history: HistoryEvent[],
@@ -162,6 +161,7 @@ export async function getHistory(
   await ws.db.runWithReadTransaction(
     [
       Stores.currencies,
+      Stores.coins,
       Stores.exchanges,
       Stores.exchangeUpdatedEvents,
       Stores.proposals,
@@ -220,15 +220,22 @@ export async function getHistory(
 
       await collectProposalHistory(tx, history, historyQuery);
 
-      await tx.iter(Stores.payEvents).forEachAsync(async (pe) => {
+      await tx.iter(Stores.payEvents).forEachAsync(async pe => {
         const proposal = await tx.get(Stores.proposals, pe.proposalId);
         if (!proposal) {
           return;
         }
+        const purchase = await tx.get(Stores.purchases, pe.proposalId);
+        if (!purchase) {
+          return;
+        }
         const orderShortInfo = getOrderShortInfo(proposal);
         if (!orderShortInfo) {
           return;
         }
+        const amountPaidWithFees = Amounts.sum(
+          purchase.payReq.coins.map(x => Amounts.parseOrThrow(x.contribution)),
+        ).amount;
         history.push({
           type: HistoryEventType.PaymentSent,
           eventId: makeEventId(HistoryEventType.PaymentSent, pe.proposalId),
@@ -236,10 +243,12 @@ export async function getHistory(
           replay: pe.isReplay,
           sessionId: pe.sessionId,
           timestamp: pe.timestamp,
+          numCoins: purchase.payReq.coins.length,
+          amountPaidWithFees: Amounts.toString(amountPaidWithFees),
         });
       });
 
-      await tx.iter(Stores.refreshGroups).forEachAsync(async (rg) => {
+      await tx.iter(Stores.refreshGroups).forEachAsync(async rg => {
         if (!rg.timestampFinished) {
           return;
         }
@@ -251,23 +260,26 @@ export async function getHistory(
         for (let i = 0; i < rg.refreshSessionPerCoin.length; i++) {
           const session = rg.refreshSessionPerCoin[i];
           numInputCoins++;
+          const c = await tx.get(Stores.coins, rg.oldCoinPubs[i]);
+          if (!c) {
+            continue;
+          }
           if (session) {
             numRefreshedInputCoins++;
             amountsRaw.push(session.amountRefreshInput);
+            amountsRaw.push(c.currentAmount);
             amountsEffective.push(session.amountRefreshOutput);
             numOutputCoins += session.newDenoms.length;
           } else {
-            const c = await tx.get(Stores.coins, rg.oldCoinPubs[i]);
-            if (!c) {
-              continue;
-            }
             amountsRaw.push(c.currentAmount);
           }
         }
         let amountRefreshedRaw = Amounts.sum(amountsRaw).amount;
         let amountRefreshedEffective: AmountJson;
         if (amountsEffective.length == 0) {
-          amountRefreshedEffective = 
Amounts.getZero(amountRefreshedRaw.currency);
+          amountRefreshedEffective = Amounts.getZero(
+            amountRefreshedRaw.currency,
+          );
         } else {
           amountRefreshedEffective = Amounts.sum(amountsEffective).amount;
         }
@@ -285,7 +297,7 @@ export async function getHistory(
         });
       });
 
-      tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async (ru) => {
+      tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async ru => {
         const reserve = await tx.get(Stores.reserves, ru.reservePub);
         if (!reserve) {
           return;
@@ -295,28 +307,31 @@ export async function getHistory(
           reserveCreationDetail = {
             type: ReserveType.TalerBankWithdraw,
             bankUrl: reserve.bankWithdrawStatusUrl,
-          }
+          };
         } else {
           reserveCreationDetail = {
             type: ReserveType.Manual,
-          }
+          };
         }
         history.push({
           type: HistoryEventType.ReserveBalanceUpdated,
-          eventId: makeEventId(HistoryEventType.ReserveBalanceUpdated, 
ru.reserveUpdateId),
+          eventId: makeEventId(
+            HistoryEventType.ReserveBalanceUpdated,
+            ru.reserveUpdateId,
+          ),
           amountExpected: ru.amountExpected,
           amountReserveBalance: ru.amountReserveBalance,
-          timestamp: reserve.timestampCreated,
+          timestamp: ru.timestamp,
           newHistoryTransactions: ru.newHistoryTransactions,
           reserveShortInfo: {
             exchangeBaseUrl: reserve.exchangeBaseUrl,
             reserveCreationDetail,
             reservePub: reserve.reservePub,
-          }
+          },
         });
       });
 
-      tx.iter(Stores.tips).forEach((tip) => {
+      tx.iter(Stores.tips).forEach(tip => {
         if (tip.acceptedTimestamp) {
           history.push({
             type: HistoryEventType.TipAccepted,
@@ -328,7 +343,7 @@ export async function getHistory(
         }
       });
 
-      tx.iter(Stores.refundEvents).forEachAsync(async (re) => {
+      tx.iter(Stores.refundEvents).forEachAsync(async re => {
         const proposal = await tx.get(Stores.proposals, re.proposalId);
         if (!proposal) {
           return;
@@ -341,7 +356,9 @@ export async function getHistory(
         if (!orderShortInfo) {
           return;
         }
-        const purchaseAmount = 
Amounts.parseOrThrow(purchase.contractTerms.amount);
+        const purchaseAmount = Amounts.parseOrThrow(
+          purchase.contractTerms.amount,
+        );
         let amountRefundedRaw = Amounts.getZero(purchaseAmount.currency);
         let amountRefundedInvalid = Amounts.getZero(purchaseAmount.currency);
         let amountRefundedEffective = Amounts.getZero(purchaseAmount.currency);
@@ -352,9 +369,16 @@ export async function getHistory(
           }
           const refundAmount = Amounts.parseOrThrow(r.perm.refund_amount);
           const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
-          amountRefundedRaw = Amounts.add(amountRefundedRaw, 
refundAmount).amount;
-          amountRefundedEffective = Amounts.add(amountRefundedEffective, 
refundAmount).amount;
-          amountRefundedEffective = Amounts.sub(amountRefundedEffective, 
refundFee).amount;
+          amountRefundedRaw = Amounts.add(amountRefundedRaw, refundAmount)
+            .amount;
+          amountRefundedEffective = Amounts.add(
+            amountRefundedEffective,
+            refundAmount,
+          ).amount;
+          amountRefundedEffective = Amounts.sub(
+            amountRefundedEffective,
+            refundFee,
+          ).amount;
         });
         Object.keys(purchase.refundState.refundsFailed).forEach((x, i) => {
           const r = purchase.refundState.refundsFailed[x];
@@ -365,7 +389,10 @@ export async function getHistory(
           const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
           amountRefundedRaw = Amounts.add(amountRefundedRaw, ra).amount;
           amountRefundedInvalid = Amounts.add(amountRefundedInvalid, 
ra).amount;
-          amountRefundedEffective = Amounts.sub(amountRefundedEffective, 
refundFee).amount;
+          amountRefundedEffective = Amounts.sub(
+            amountRefundedEffective,
+            refundFee,
+          ).amount;
         });
         history.push({
           type: HistoryEventType.Refund,
diff --git a/src/operations/pending.ts b/src/operations/pending.ts
index ffa23f10..36018085 100644
--- a/src/operations/pending.ts
+++ b/src/operations/pending.ts
@@ -224,6 +224,8 @@ async function gatherRefreshPending(
       type: PendingOperationType.Refresh,
       givesLifeness: true,
       refreshGroupId: r.refreshGroupId,
+      finishedPerCoin: r.finishedPerCoin,
+      retryInfo: r.retryInfo,
     });
   });
 }
diff --git a/src/operations/refresh.ts b/src/operations/refresh.ts
index f602221a..8390cac5 100644
--- a/src/operations/refresh.ts
+++ b/src/operations/refresh.ts
@@ -144,10 +144,22 @@ async function refreshCreateSession(
           return;
         }
         rg.finishedPerCoin[coinIndex] = true;
+        rg.finishedPerCoin[coinIndex] = true;
+        let allDone = true;
+        for (const f of rg.finishedPerCoin) {
+          if (!f) {
+            allDone = false;
+            break;
+          }
+        }
+        if (allDone) {
+          rg.timestampFinished = getTimestampNow();
+          rg.retryInfo = initRetryInfo(false);
+        }
         await tx.put(Stores.refreshGroups, rg);
       },
     );
-    ws.notify({ type: NotificationType.RefreshRefused });
+    ws.notify({ type: NotificationType.RefreshUnwarranted });
     return;
   }
 
diff --git a/src/operations/reserves.ts b/src/operations/reserves.ts
index 649bf75f..7be92782 100644
--- a/src/operations/reserves.ts
+++ b/src/operations/reserves.ts
@@ -34,12 +34,14 @@ import {
   updateRetryInfoTimeout,
   ReserveUpdatedEventRecord,
 } from "../types/dbTypes";
-import {
-  TransactionAbort,
-} from "../util/query";
+import { TransactionAbort } from "../util/query";
 import { Logger } from "../util/logging";
 import * as Amounts from "../util/amounts";
-import { updateExchangeFromUrl, getExchangeTrust, getExchangePaytoUri } from 
"./exchanges";
+import {
+  updateExchangeFromUrl,
+  getExchangeTrust,
+  getExchangePaytoUri,
+} from "./exchanges";
 import { WithdrawOperationStatusResponse } from "../types/talerTypes";
 import { assertUnreachable } from "../util/assertUnreachable";
 import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
@@ -49,7 +51,10 @@ import {
   processWithdrawSession,
   getBankWithdrawalInfo,
 } from "./withdraw";
-import { guardOperationException, OperationFailedAndReportedError } from 
"./errors";
+import {
+  guardOperationException,
+  OperationFailedAndReportedError,
+} from "./errors";
 import { NotificationType } from "../types/notifications";
 import { codecForReserveStatus } from "../types/ReserveStatus";
 
@@ -206,7 +211,6 @@ export async function processReserve(
   });
 }
 
-
 async function registerReserveWithBank(
   ws: InternalWalletState,
   reservePub: string,
@@ -231,7 +235,6 @@ async function registerReserveWithBank(
     reserve_pub: reservePub,
     selected_exchange: reserve.exchangeWire,
   });
-  console.log("got response", bankResp);
   await ws.db.mutate(Stores.reserves, reservePub, r => {
     switch (r.reserveStatus) {
       case ReserveRecordStatus.REGISTERING_BANK:
@@ -245,7 +248,7 @@ async function registerReserveWithBank(
     r.retryInfo = initRetryInfo();
     return r;
   });
-  ws.notify( { type: NotificationType.Wildcard });
+  ws.notify({ type: NotificationType.Wildcard });
   return processReserveBankStatus(ws, reservePub);
 }
 
@@ -282,14 +285,16 @@ async function processReserveBankStatusImpl(
   try {
     const statusResp = await ws.http.get(bankStatusUrl);
     if (statusResp.status !== 200) {
-      throw Error(`unexpected status ${statusResp.status} for bank status 
query`);
+      throw Error(
+        `unexpected status ${statusResp.status} for bank status query`,
+      );
     }
     status = WithdrawOperationStatusResponse.checked(await statusResp.json());
   } catch (e) {
     throw e;
   }
 
-  ws.notify( { type: NotificationType.Wildcard });
+  ws.notify({ type: NotificationType.Wildcard });
 
   if (status.selection_done) {
     if (reserve.reserveStatus === ReserveRecordStatus.REGISTERING_BANK) {
@@ -330,7 +335,7 @@ async function processReserveBankStatusImpl(
     });
     await incrementReserveRetry(ws, reservePub, undefined);
   }
-  ws.notify( { type: NotificationType.Wildcard });
+  ws.notify({ type: NotificationType.Wildcard });
 }
 
 async function incrementReserveRetry(
@@ -351,7 +356,12 @@ async function incrementReserveRetry(
     r.lastError = err;
     await tx.put(Stores.reserves, r);
   });
-  ws.notify({ type: NotificationType.ReserveOperationError });
+  if (err) {
+    ws.notify({
+      type: NotificationType.ReserveOperationError,
+      operationError: err,
+    });
+  }
 }
 
 /**
@@ -386,7 +396,7 @@ async function updateReserve(
       return;
     }
     if (resp.status !== 200) {
-      throw Error(`unexpected status code ${resp.status} for reserve/status`)
+      throw Error(`unexpected status code ${resp.status} for reserve/status`);
     }
   } catch (e) {
     const m = e.message;
@@ -400,68 +410,73 @@ async function updateReserve(
   const respJson = await resp.json();
   const reserveInfo = codecForReserveStatus.decode(respJson);
   const balance = Amounts.parseOrThrow(reserveInfo.balance);
-  await ws.db.runWithWriteTransaction([Stores.reserves, 
Stores.reserveUpdatedEvents], async (tx) => {
-    const r = await tx.get(Stores.reserves, reservePub);
-    if (!r) {
-      return;
-    }
-    if (r.reserveStatus !== ReserveRecordStatus.QUERYING_STATUS) {
-      return;
-    }
-
-    const newHistoryTransactions = 
reserveInfo.history.slice(r.reserveTransactions.length);
-
-    const reserveUpdateId = encodeCrock(getRandomBytes(32));
-
-    // FIXME: check / compare history!
-    if (!r.lastSuccessfulStatusQuery) {
-      // FIXME: check if this matches initial expectations
-      r.amountWithdrawRemaining = balance;
-      const reserveUpdate: ReserveUpdatedEventRecord = {
-        reservePub: r.reservePub,
-        timestamp: getTimestampNow(),
-        amountReserveBalance: Amounts.toString(balance),
-        amountExpected: Amounts.toString(reserve.amountInitiallyRequested),
-        newHistoryTransactions,
-        reserveUpdateId,
-      };
-      await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
-    } else {
-      const expectedBalance = Amounts.sub(
-        r.amountWithdrawAllocated,
-        r.amountWithdrawCompleted,
-      );
-      const cmp = Amounts.cmp(balance, expectedBalance.amount);
-      if (cmp == 0) {
-        // Nothing changed.
+  await ws.db.runWithWriteTransaction(
+    [Stores.reserves, Stores.reserveUpdatedEvents],
+    async tx => {
+      const r = await tx.get(Stores.reserves, reservePub);
+      if (!r) {
+        return;
+      }
+      if (r.reserveStatus !== ReserveRecordStatus.QUERYING_STATUS) {
         return;
       }
-      if (cmp > 0) {
-        const extra = Amounts.sub(balance, expectedBalance.amount).amount;
-        r.amountWithdrawRemaining = Amounts.add(
-          r.amountWithdrawRemaining,
-          extra,
-        ).amount;
+
+      const newHistoryTransactions = reserveInfo.history.slice(
+        r.reserveTransactions.length,
+      );
+
+      const reserveUpdateId = encodeCrock(getRandomBytes(32));
+
+      // FIXME: check / compare history!
+      if (!r.lastSuccessfulStatusQuery) {
+        // FIXME: check if this matches initial expectations
+        r.amountWithdrawRemaining = balance;
+        const reserveUpdate: ReserveUpdatedEventRecord = {
+          reservePub: r.reservePub,
+          timestamp: getTimestampNow(),
+          amountReserveBalance: Amounts.toString(balance),
+          amountExpected: Amounts.toString(reserve.amountInitiallyRequested),
+          newHistoryTransactions,
+          reserveUpdateId,
+        };
+        await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
       } else {
-        // We're missing some money.
+        const expectedBalance = Amounts.sub(
+          r.amountWithdrawAllocated,
+          r.amountWithdrawCompleted,
+        );
+        const cmp = Amounts.cmp(balance, expectedBalance.amount);
+        if (cmp == 0) {
+          // Nothing changed.
+          return;
+        }
+        if (cmp > 0) {
+          const extra = Amounts.sub(balance, expectedBalance.amount).amount;
+          r.amountWithdrawRemaining = Amounts.add(
+            r.amountWithdrawRemaining,
+            extra,
+          ).amount;
+        } else {
+          // We're missing some money.
+        }
+        const reserveUpdate: ReserveUpdatedEventRecord = {
+          reservePub: r.reservePub,
+          timestamp: getTimestampNow(),
+          amountReserveBalance: Amounts.toString(balance),
+          amountExpected: Amounts.toString(expectedBalance.amount),
+          newHistoryTransactions,
+          reserveUpdateId,
+        };
+        await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
       }
-      const reserveUpdate: ReserveUpdatedEventRecord = {
-        reservePub: r.reservePub,
-        timestamp: getTimestampNow(),
-        amountReserveBalance: Amounts.toString(balance),
-        amountExpected: Amounts.toString(expectedBalance.amount),
-        newHistoryTransactions,
-        reserveUpdateId,
-      };
-      await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
-    }
-    r.lastSuccessfulStatusQuery = getTimestampNow();
-    r.reserveStatus = ReserveRecordStatus.WITHDRAWING;
-    r.retryInfo = initRetryInfo();
-    r.reserveTransactions = reserveInfo.history;
-    await tx.put(Stores.reserves, r);
-  });
-  ws.notify( { type: NotificationType.ReserveUpdated });
+      r.lastSuccessfulStatusQuery = getTimestampNow();
+      r.reserveStatus = ReserveRecordStatus.WITHDRAWING;
+      r.retryInfo = initRetryInfo();
+      r.reserveTransactions = reserveInfo.history;
+      await tx.put(Stores.reserves, r);
+    },
+  );
+  ws.notify({ type: NotificationType.ReserveUpdated });
 }
 
 async function processReserveImpl(
@@ -655,8 +670,6 @@ async function depleteReserve(
   }
 }
 
-
-
 export async function createTalerWithdrawReserve(
   ws: InternalWalletState,
   talerWithdrawUri: string,
@@ -683,4 +696,4 @@ export async function createTalerWithdrawReserve(
     reservePub: reserve.reservePub,
     confirmTransferUrl: withdrawInfo.confirmTransferUrl,
   };
-}
\ No newline at end of file
+}
diff --git a/src/types/history.ts b/src/types/history.ts
index 8b46276b..aa35ab96 100644
--- a/src/types/history.ts
+++ b/src/types/history.ts
@@ -485,6 +485,16 @@ export interface HistoryPaymentSent {
    */
   replay: boolean;
 
+  /**
+   * Number of coins that were involved in the payment.
+   */
+  numCoins: number;
+
+  /**
+   * Amount that was paid, including deposit and wire fees.
+   */
+  amountPaidWithFees: string;
+
   /**
    * Session ID that the payment was (re-)submitted under.
    */
diff --git a/src/types/notifications.ts b/src/types/notifications.ts
index c64d33bf..30ede151 100644
--- a/src/types/notifications.ts
+++ b/src/types/notifications.ts
@@ -1,3 +1,5 @@
+import { OperationError } from "./walletTypes";
+
 /*
  This file is part of GNU Taler
  (C) 2019 GNUnet e.V.
@@ -29,7 +31,7 @@ export const enum NotificationType {
   RefreshRevealed = "refresh-revealed",
   RefreshMelted = "refresh-melted",
   RefreshStarted = "refresh-started",
-  RefreshRefused = "refresh-refused",
+  RefreshUnwarranted = "refresh-unwarranted",
   ReserveUpdated = "reserve-updated",
   ReserveConfirmed = "reserve-confirmed",
   ReserveDepleted = "reserve-depleted",
@@ -100,7 +102,7 @@ export interface RefreshStartedNotification {
 }
 
 export interface RefreshRefusedNotification {
-  type: NotificationType.RefreshRefused;
+  type: NotificationType.RefreshUnwarranted;
 }
 
 export interface ReserveUpdatedNotification {
@@ -170,6 +172,7 @@ export interface WithdrawOperationErrorNotification {
 
 export interface ReserveOperationErrorNotification {
   type: NotificationType.ReserveOperationError;
+  operationError: OperationError;
 }
 
 export interface ReserveCreatedNotification {
diff --git a/src/types/pending.ts b/src/types/pending.ts
index 53932e8f..efb97f53 100644
--- a/src/types/pending.ts
+++ b/src/types/pending.ts
@@ -87,6 +87,8 @@ export interface PendingRefreshOperation {
   type: PendingOperationType.Refresh;
   lastError?: OperationError;
   refreshGroupId: string;
+  finishedPerCoin: boolean[];
+  retryInfo: RetryInfo;
 }
 
 export interface PendingProposalDownloadOperation {

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

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