gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: introduce refund groups, reac


From: gnunet
Subject: [taler-wallet-core] branch master updated: introduce refund groups, react correctly to 410 Gone for /refund
Date: Sun, 15 Dec 2019 19:04:21 +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 857c0ab4 introduce refund groups, react correctly to 410 Gone for 
/refund
857c0ab4 is described below

commit 857c0ab4cd2253a0e1d53e3372a1ff1565cb4150
Author: Florian Dold <address@hidden>
AuthorDate: Sun Dec 15 19:04:14 2019 +0100

    introduce refund groups, react correctly to 410 Gone for /refund
---
 src/operations/pay.ts     | 467 ++++------------------------------------------
 src/operations/pending.ts |   4 +-
 src/types/dbTypes.ts      |  81 +++++++-
 src/util/http.ts          |   5 +
 src/wallet.ts             |  21 +--
 tsconfig.json             |   1 +
 6 files changed, 130 insertions(+), 449 deletions(-)

diff --git a/src/operations/pay.ts b/src/operations/pay.ts
index ccb55305..388db94b 100644
--- a/src/operations/pay.ts
+++ b/src/operations/pay.ts
@@ -1,6 +1,6 @@
 /*
  This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
+ (C) Taler Systems S.A.
 
  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
@@ -14,6 +14,16 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+/**
+ * Implementation of the payment operation, including downloading and
+ * claiming of proposals.
+ *
+ * @author Florian Dold
+ */
+
+/**
+ * Imports.
+ */
 import { AmountJson } from "../util/amounts";
 import {
   Auditor,
@@ -36,9 +46,6 @@ import {
   OperationError,
   RefreshReason,
 } from "../types/walletTypes";
-import {
-  Database
-} from "../util/query";
 import {
   Stores,
   CoinStatus,
@@ -49,6 +56,7 @@ import {
   ProposalStatus,
   initRetryInfo,
   updateRetryInfoTimeout,
+  RefundReason,
 } from "../types/dbTypes";
 import * as Amounts from "../util/amounts";
 import {
@@ -56,7 +64,6 @@ import {
   strcmp,
   canonicalJson,
   extractTalerStampOrThrow,
-  extractTalerDurationOrThrow,
   extractTalerDuration,
 } from "../util/helpers";
 import { Logger } from "../util/logging";
@@ -69,8 +76,8 @@ import {
 import { getTotalRefreshCost, createRefreshGroup } from "./refresh";
 import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
 import { guardOperationException } from "./errors";
-import { assertUnreachable } from "../util/assertUnreachable";
 import { NotificationType } from "../types/notifications";
+import { acceptRefundResponse } from "./refund";
 
 export interface SpeculativePayData {
   payCoinInfo: PayCoinInfo;
@@ -237,15 +244,13 @@ async function getCoinsForPayment(
       continue;
     }
 
-    const coins = await ws.db.iterIndex(
-      Stores.coins.exchangeBaseUrlIndex,
-      exchange.baseUrl,
-    ).toArray();
+    const coins = await ws.db
+      .iterIndex(Stores.coins.exchangeBaseUrlIndex, exchange.baseUrl)
+      .toArray();
 
-    const denoms = await ws.db.iterIndex(
-      Stores.denominations.exchangeBaseUrlIndex,
-      exchange.baseUrl,
-    ).toArray();
+    const denoms = await ws.db
+      .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchange.baseUrl)
+      .toArray();
 
     if (!coins || coins.length === 0) {
       continue;
@@ -353,8 +358,6 @@ async function recordConfirmPay(
     lastSessionId: sessionId,
     merchantSig: d.merchantSig,
     payReq,
-    refundsDone: {},
-    refundsPending: {},
     acceptTimestamp: getTimestampNow(),
     lastRefundStatusTimestamp: undefined,
     proposalId: proposal.proposalId,
@@ -368,6 +371,12 @@ async function recordConfirmPay(
     firstSuccessfulPayTimestamp: undefined,
     autoRefundDeadline: undefined,
     paymentSubmitPending: true,
+    refundState: {
+      refundGroups: [],
+      refundsDone: {},
+      refundsFailed: {},
+      refundsPending: {},
+    },
   };
 
   await ws.db.runWithWriteTransaction(
@@ -447,7 +456,12 @@ export async function abortFailedPayment(
   }
 
   const refundResponse = MerchantRefundResponse.checked(await resp.json());
-  await acceptRefundResponse(ws, purchase.proposalId, refundResponse);
+  await acceptRefundResponse(
+    ws,
+    purchase.proposalId,
+    refundResponse,
+    RefundReason.AbortRefund,
+  );
 
   await ws.db.runWithWriteTransaction([Stores.purchases], async tx => {
     const p = await tx.get(Stores.purchases, proposalId);
@@ -502,50 +516,6 @@ async function incrementPurchasePayRetry(
   ws.notify({ type: NotificationType.PayOperationError });
 }
 
-async function incrementPurchaseQueryRefundRetry(
-  ws: InternalWalletState,
-  proposalId: string,
-  err: OperationError | undefined,
-): Promise<void> {
-  console.log("incrementing purchase refund query retry with error", err);
-  await ws.db.runWithWriteTransaction([Stores.purchases], async tx => {
-    const pr = await tx.get(Stores.purchases, proposalId);
-    if (!pr) {
-      return;
-    }
-    if (!pr.refundStatusRetryInfo) {
-      return;
-    }
-    pr.refundStatusRetryInfo.retryCounter++;
-    updateRetryInfoTimeout(pr.refundStatusRetryInfo);
-    pr.lastRefundStatusError = err;
-    await tx.put(Stores.purchases, pr);
-  });
-  ws.notify({ type: NotificationType.RefundStatusOperationError });
-}
-
-async function incrementPurchaseApplyRefundRetry(
-  ws: InternalWalletState,
-  proposalId: string,
-  err: OperationError | undefined,
-): Promise<void> {
-  console.log("incrementing purchase refund apply retry with error", err);
-  await ws.db.runWithWriteTransaction([Stores.purchases], async tx => {
-    const pr = await tx.get(Stores.purchases, proposalId);
-    if (!pr) {
-      return;
-    }
-    if (!pr.refundApplyRetryInfo) {
-      return;
-    }
-    pr.refundApplyRetryInfo.retryCounter++;
-    updateRetryInfoTimeout(pr.refundStatusRetryInfo);
-    pr.lastRefundApplyError = err;
-    await tx.put(Stores.purchases, pr);
-  });
-  ws.notify({ type: NotificationType.RefundApplyOperationError });
-}
-
 export async function processDownloadProposal(
   ws: InternalWalletState,
   proposalId: string,
@@ -695,11 +665,11 @@ async function startDownloadProposal(
     downloadSessionId: sessionId,
   };
 
-  await ws.db.runWithWriteTransaction([Stores.proposals], async (tx) => {
-    const existingRecord = await 
tx.getIndexed(Stores.proposals.urlAndOrderIdIndex, [
-      merchantBaseUrl,
-      orderId,
-    ]);
+  await ws.db.runWithWriteTransaction([Stores.proposals], async tx => {
+    const existingRecord = await tx.getIndexed(
+      Stores.proposals.urlAndOrderIdIndex,
+      [merchantBaseUrl, orderId],
+    );
     if (existingRecord) {
       // Created concurrently
       return;
@@ -793,7 +763,11 @@ export async function submitPay(
       for (let c of modifiedCoins) {
         await tx.put(Stores.coins, c);
       }
-      await createRefreshGroup(tx, modifiedCoins.map((x) => ({ coinPub: 
x.coinPub })), RefreshReason.Pay);
+      await createRefreshGroup(
+        tx,
+        modifiedCoins.map(x => ({ coinPub: x.coinPub })),
+        RefreshReason.Pay,
+      );
       await tx.put(Stores.purchases, purchase);
     },
   );
@@ -1069,192 +1043,6 @@ export async function confirmPay(
   return submitPay(ws, proposalId);
 }
 
-export async function getFullRefundFees(
-  ws: InternalWalletState,
-  refundPermissions: MerchantRefundPermission[],
-): Promise<AmountJson> {
-  if (refundPermissions.length === 0) {
-    throw Error("no refunds given");
-  }
-  const coin0 = await ws.db.get(
-    Stores.coins,
-    refundPermissions[0].coin_pub,
-  );
-  if (!coin0) {
-    throw Error("coin not found");
-  }
-  let feeAcc = Amounts.getZero(
-    Amounts.parseOrThrow(refundPermissions[0].refund_amount).currency,
-  );
-
-  const denoms = await ws.db.iterIndex(
-    Stores.denominations.exchangeBaseUrlIndex,
-    coin0.exchangeBaseUrl,
-  ).toArray();
-
-  for (const rp of refundPermissions) {
-    const coin = await ws.db.get(Stores.coins, rp.coin_pub);
-    if (!coin) {
-      throw Error("coin not found");
-    }
-    const denom = await ws.db.get(Stores.denominations, [
-      coin0.exchangeBaseUrl,
-      coin.denomPub,
-    ]);
-    if (!denom) {
-      throw Error(`denom not found (${coin.denomPub})`);
-    }
-    // FIXME:  this assumes that the refund already happened.
-    // When it hasn't, the refresh cost is inaccurate.  To fix this,
-    // we need introduce a flag to tell if a coin was refunded or
-    // refreshed normally (and what about incremental refunds?)
-    const refundAmount = Amounts.parseOrThrow(rp.refund_amount);
-    const refundFee = Amounts.parseOrThrow(rp.refund_fee);
-    const refreshCost = getTotalRefreshCost(
-      denoms,
-      denom,
-      Amounts.sub(refundAmount, refundFee).amount,
-    );
-    feeAcc = Amounts.add(feeAcc, refreshCost, refundFee).amount;
-  }
-  return feeAcc;
-}
-
-async function acceptRefundResponse(
-  ws: InternalWalletState,
-  proposalId: string,
-  refundResponse: MerchantRefundResponse,
-): Promise<void> {
-  const refundPermissions = refundResponse.refund_permissions;
-
-  let numNewRefunds = 0;
-
-  await ws.db.runWithWriteTransaction([Stores.purchases], async tx => {
-    const p = await tx.get(Stores.purchases, proposalId);
-    if (!p) {
-      console.error("purchase not found, not adding refunds");
-      return;
-    }
-
-    if (!p.refundStatusRequested) {
-      return;
-    }
-
-    for (const perm of refundPermissions) {
-      if (
-        !p.refundsPending[perm.merchant_sig] &&
-        !p.refundsDone[perm.merchant_sig]
-      ) {
-        p.refundsPending[perm.merchant_sig] = perm;
-        numNewRefunds++;
-      }
-    }
-
-    // Are we done with querying yet, or do we need to do another round
-    // after a retry delay?
-    let queryDone = true;
-
-    if (numNewRefunds === 0) {
-      if (
-        p.autoRefundDeadline &&
-        p.autoRefundDeadline.t_ms > getTimestampNow().t_ms
-      ) {
-        queryDone = false;
-      }
-    }
-
-    if (queryDone) {
-      p.lastRefundStatusTimestamp = getTimestampNow();
-      p.lastRefundStatusError = undefined;
-      p.refundStatusRetryInfo = initRetryInfo();
-      p.refundStatusRequested = false;
-      console.log("refund query done");
-    } else {
-      // No error, but we need to try again!
-      p.lastRefundStatusTimestamp = getTimestampNow();
-      p.refundStatusRetryInfo.retryCounter++;
-      updateRetryInfoTimeout(p.refundStatusRetryInfo);
-      p.lastRefundStatusError = undefined;
-      console.log("refund query not done");
-    }
-
-    if (numNewRefunds) {
-      p.lastRefundApplyError = undefined;
-      p.refundApplyRetryInfo = initRetryInfo();
-    }
-
-    await tx.put(Stores.purchases, p);
-  });
-  ws.notify({
-    type: NotificationType.RefundQueried,
-  });
-  if (numNewRefunds > 0) {
-    await processPurchaseApplyRefund(ws, proposalId);
-  }
-}
-
-async function startRefundQuery(
-  ws: InternalWalletState,
-  proposalId: string,
-): Promise<void> {
-  const success = await ws.db.runWithWriteTransaction(
-    [Stores.purchases],
-    async tx => {
-      const p = await tx.get(Stores.purchases, proposalId);
-      if (!p) {
-        console.log("no purchase found for refund URL");
-        return false;
-      }
-      p.refundStatusRequested = true;
-      p.lastRefundStatusError = undefined;
-      p.refundStatusRetryInfo = initRetryInfo();
-      await tx.put(Stores.purchases, p);
-      return true;
-    },
-  );
-
-  if (!success) {
-    return;
-  }
-
-  ws.notify({
-    type: NotificationType.RefundStarted,
-  });
-
-  await processPurchaseQueryRefund(ws, proposalId);
-}
-
-/**
- * Accept a refund, return the contract hash for the contract
- * that was involved in the refund.
- */
-export async function applyRefund(
-  ws: InternalWalletState,
-  talerRefundUri: string,
-): Promise<string> {
-  const parseResult = parseRefundUri(talerRefundUri);
-
-  console.log("applying refund");
-
-  if (!parseResult) {
-    throw Error("invalid refund URI");
-  }
-
-  const purchase = await ws.db.getIndexed(
-    Stores.purchases.orderIdIndex,
-    [parseResult.merchantBaseUrl, parseResult.orderId],
-  );
-
-  if (!purchase) {
-    throw Error("no purchase for the taler://refund/ URI was found");
-  }
-
-  console.log("processing purchase for refund");
-  await startRefundQuery(ws, purchase.proposalId);
-
-  return purchase.contractTermsHash;
-}
-
 export async function processPurchasePay(
   ws: InternalWalletState,
   proposalId: string,
@@ -1298,176 +1086,3 @@ async function processPurchasePayImpl(
   logger.trace(`processing purchase pay ${proposalId}`);
   await submitPay(ws, proposalId);
 }
-
-export async function processPurchaseQueryRefund(
-  ws: InternalWalletState,
-  proposalId: string,
-  forceNow: boolean = false,
-): Promise<void> {
-  const onOpErr = (e: OperationError) =>
-    incrementPurchaseQueryRefundRetry(ws, proposalId, e);
-  await guardOperationException(
-    () => processPurchaseQueryRefundImpl(ws, proposalId, forceNow),
-    onOpErr,
-  );
-}
-
-async function resetPurchaseQueryRefundRetry(
-  ws: InternalWalletState,
-  proposalId: string,
-) {
-  await ws.db.mutate(Stores.purchases, proposalId, x => {
-    if (x.refundStatusRetryInfo.active) {
-      x.refundStatusRetryInfo = initRetryInfo();
-    }
-    return x;
-  });
-}
-
-async function processPurchaseQueryRefundImpl(
-  ws: InternalWalletState,
-  proposalId: string,
-  forceNow: boolean,
-): Promise<void> {
-  if (forceNow) {
-    await resetPurchaseQueryRefundRetry(ws, proposalId);
-  }
-  const purchase = await ws.db.get(Stores.purchases, proposalId);
-  if (!purchase) {
-    return;
-  }
-  if (!purchase.refundStatusRequested) {
-    return;
-  }
-
-  const refundUrlObj = new URL(
-    "refund",
-    purchase.contractTerms.merchant_base_url,
-  );
-  refundUrlObj.searchParams.set("order_id", purchase.contractTerms.order_id);
-  const refundUrl = refundUrlObj.href;
-  let resp;
-  try {
-    resp = await ws.http.get(refundUrl);
-  } catch (e) {
-    console.error("error downloading refund permission", e);
-    throw e;
-  }
-  if (resp.status !== 200) {
-    throw Error(`unexpected status code (${resp.status}) for /refund`);
-  }
-
-  const refundResponse = MerchantRefundResponse.checked(await resp.json());
-  await acceptRefundResponse(ws, proposalId, refundResponse);
-}
-
-export async function processPurchaseApplyRefund(
-  ws: InternalWalletState,
-  proposalId: string,
-  forceNow: boolean = false,
-): Promise<void> {
-  const onOpErr = (e: OperationError) =>
-    incrementPurchaseApplyRefundRetry(ws, proposalId, e);
-  await guardOperationException(
-    () => processPurchaseApplyRefundImpl(ws, proposalId, forceNow),
-    onOpErr,
-  );
-}
-
-async function resetPurchaseApplyRefundRetry(
-  ws: InternalWalletState,
-  proposalId: string,
-) {
-  await ws.db.mutate(Stores.purchases, proposalId, x => {
-    if (x.refundApplyRetryInfo.active) {
-      x.refundApplyRetryInfo = initRetryInfo();
-    }
-    return x;
-  });
-}
-
-async function processPurchaseApplyRefundImpl(
-  ws: InternalWalletState,
-  proposalId: string,
-  forceNow: boolean,
-): Promise<void> {
-  if (forceNow) {
-    await resetPurchaseApplyRefundRetry(ws, proposalId);
-  }
-  const purchase = await ws.db.get(Stores.purchases, proposalId);
-  if (!purchase) {
-    console.error("not submitting refunds, payment not found:");
-    return;
-  }
-  const pendingKeys = Object.keys(purchase.refundsPending);
-  if (pendingKeys.length === 0) {
-    console.log("no pending refunds");
-    return;
-  }
-  for (const pk of pendingKeys) {
-    const perm = purchase.refundsPending[pk];
-    const req: RefundRequest = {
-      coin_pub: perm.coin_pub,
-      h_contract_terms: purchase.contractTermsHash,
-      merchant_pub: purchase.contractTerms.merchant_pub,
-      merchant_sig: perm.merchant_sig,
-      refund_amount: perm.refund_amount,
-      refund_fee: perm.refund_fee,
-      rtransaction_id: perm.rtransaction_id,
-    };
-    console.log("sending refund permission", perm);
-    // FIXME: not correct once we support multiple exchanges per payment
-    const exchangeUrl = purchase.payReq.coins[0].exchange_url;
-    const reqUrl = new URL("refund", exchangeUrl);
-    const resp = await ws.http.postJson(reqUrl.href, req);
-    console.log("sent refund permission");
-    if (resp.status !== 200) {
-      console.error("refund failed", resp);
-      continue;
-    }
-
-    let allRefundsProcessed = false;
-
-    await ws.db.runWithWriteTransaction(
-      [Stores.purchases, Stores.coins, Stores.refreshGroups],
-      async tx => {
-        const p = await tx.get(Stores.purchases, proposalId);
-        if (!p) {
-          return;
-        }
-        if (p.refundsPending[pk]) {
-          p.refundsDone[pk] = p.refundsPending[pk];
-          delete p.refundsPending[pk];
-        }
-        if (Object.keys(p.refundsPending).length === 0) {
-          p.refundStatusRetryInfo = initRetryInfo();
-          p.lastRefundStatusError = undefined;
-          allRefundsProcessed = true;
-        }
-        await tx.put(Stores.purchases, p);
-        const c = await tx.get(Stores.coins, perm.coin_pub);
-        if (!c) {
-          console.warn("coin not found, can't apply refund");
-          return;
-        }
-        const refundAmount = Amounts.parseOrThrow(perm.refund_amount);
-        const refundFee = Amounts.parseOrThrow(perm.refund_fee);
-        c.status = CoinStatus.Dormant;
-        c.currentAmount = Amounts.add(c.currentAmount, refundAmount).amount;
-        c.currentAmount = Amounts.sub(c.currentAmount, refundFee).amount;
-        await tx.put(Stores.coins, c);
-        await createRefreshGroup(tx, [{ coinPub: perm.coin_pub }], 
RefreshReason.Refund);
-      },
-    );
-    if (allRefundsProcessed) {
-      ws.notify({
-        type: NotificationType.RefundFinished,
-      });
-    }
-  }
-
-  ws.notify({
-    type: NotificationType.RefundsSubmitted,
-    proposalId,
-  });
-}
diff --git a/src/operations/pending.ts b/src/operations/pending.ts
index 27892df0..f0b29792 100644
--- a/src/operations/pending.ts
+++ b/src/operations/pending.ts
@@ -365,9 +365,9 @@ async function gatherPurchasePending(
         });
       }
     }
-    const numRefundsPending = Object.keys(pr.refundsPending).length;
+    const numRefundsPending = 
Object.keys(pr.refundState.refundsPending).length;
     if (numRefundsPending > 0) {
-      const numRefundsDone = Object.keys(pr.refundsDone).length;
+      const numRefundsDone = Object.keys(pr.refundState.refundsDone).length;
       resp.nextRetryDelay = updateRetryDelay(
         resp.nextRetryDelay,
         now,
diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts
index c05aa68d..9d2f6fe5 100644
--- a/src/types/dbTypes.ts
+++ b/src/types/dbTypes.ts
@@ -1002,6 +1002,63 @@ export interface WireFee {
   sig: string;
 }
 
+/**
+ * Record to store information about a refund event.
+ * 
+ * All information about a refund is stored with the purchase,
+ * this event is just for the history.
+ * 
+ * The event is only present for completed refunds.
+ */
+export interface RefundEventRecord {
+  timestamp: Timestamp;
+  refundGroupId: string;
+  proposalId: string;
+}
+
+export interface RefundInfo {
+  refundGroupId: string;
+  perm: MerchantRefundPermission;
+}
+
+export const enum RefundReason {
+  /**
+   * Normal refund given by the merchant.
+   */
+  NormalRefund = "normal-refund",
+  /**
+   * Refund from an aborted payment.
+   */
+  AbortRefund = "abort-refund",
+}
+
+export interface RefundGroupInfo {
+  timestampQueried: Timestamp;
+  reason: RefundReason;
+}
+
+export interface PurchaseRefundState {
+  /**
+   * Information regarding each group of refunds we receive at once.
+   */
+  refundGroups: RefundGroupInfo[];
+
+  /**
+   * Pending refunds for the purchase.
+   */
+  refundsPending: { [refundSig: string]: RefundInfo };
+
+  /**
+   * Applied refunds for the purchase.
+   */
+  refundsDone: { [refundSig: string]: RefundInfo };
+
+  /**
+   * Submitted refunds for the purchase.
+   */
+  refundsFailed: { [refundSig: string]: RefundInfo };
+}
+
 /**
  * Record that stores status information about one purchase, starting from when
  * the customer accepts a proposal.  Includes refund status if applicable.
@@ -1034,17 +1091,11 @@ export interface PurchaseRecord {
    */
   merchantSig: string;
 
-  firstSuccessfulPayTimestamp: Timestamp | undefined;
-
   /**
-   * Pending refunds for the purchase.
+   * Timestamp of the first time that sending a payment to the merchant
+   * for this purchase was successful.
    */
-  refundsPending: { [refundSig: string]: MerchantRefundPermission };
-
-  /**
-   * Submitted refunds for the purchase.
-   */
-  refundsDone: { [refundSig: string]: MerchantRefundPermission };
+  firstSuccessfulPayTimestamp: Timestamp | undefined;
 
   /**
    * When was the purchase made?
@@ -1052,6 +1103,11 @@ export interface PurchaseRecord {
    */
   acceptTimestamp: Timestamp;
 
+  /**
+   * State of refunds for this proposal.
+   */
+  refundState: PurchaseRefundState;
+
   /**
    * When was the last refund made?
    * Set to 0 if no refund was made on the purchase.
@@ -1370,6 +1426,12 @@ export namespace Stores {
     }
   }
 
+  class RefundEventsStore extends Store<RefundEventRecord> {
+    constructor() {
+      super("refundEvents", { keyPath: "refundGroupId" });
+    }
+  }
+
   class BankWithdrawUrisStore extends Store<BankWithdrawUriRecord> {
     constructor() {
       super("bankWithdrawUris", { keyPath: "talerWithdrawUri" });
@@ -1394,6 +1456,7 @@ export namespace Stores {
   export const senderWires = new SenderWiresStore();
   export const withdrawalSession = new WithdrawalSessionsStore();
   export const bankWithdrawUris = new BankWithdrawUrisStore();
+  export const refundEvents = new RefundEventsStore();
 }
 
 /* tslint:enable:completed-docs */
diff --git a/src/util/http.ts b/src/util/http.ts
index 79039f51..93c748d7 100644
--- a/src/util/http.ts
+++ b/src/util/http.ts
@@ -33,6 +33,11 @@ export interface HttpRequestOptions {
   headers?: { [name: string]: string };
 }
 
+export enum HttpResponseStatus {
+  Ok = 200,
+  Gone = 210,
+}
+
 /**
  * Headers, roughly modeled after the fetch API's headers object.
  */
diff --git a/src/wallet.ts b/src/wallet.ts
index 163f3def..a4e20107 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -42,11 +42,7 @@ import {
   preparePay,
   confirmPay,
   processDownloadProposal,
-  applyRefund,
-  getFullRefundFees,
   processPurchasePay,
-  processPurchaseQueryRefund,
-  processPurchaseApplyRefund,
 } from "./operations/pay";
 
 import {
@@ -107,6 +103,7 @@ import { AsyncOpMemoSingle } from "./util/asyncMemo";
 import { PendingOperationInfo, PendingOperationsResponse, PendingOperationType 
} from "./types/pending";
 import { WalletNotification, NotificationType } from "./types/notifications";
 import { HistoryQuery, HistoryEvent } from "./types/history";
+import { processPurchaseQueryRefund, processPurchaseApplyRefund, 
getFullRefundFees, applyRefund } from "./operations/refund";
 
 /**
  * Wallet protocol version spoken with the exchange
@@ -695,21 +692,21 @@ export class Wallet {
     if (!purchase) {
       throw Error("unknown purchase");
     }
-    const refundsDoneAmounts = Object.values(purchase.refundsDone).map(x =>
-      Amounts.parseOrThrow(x.refund_amount),
+    const refundsDoneAmounts = 
Object.values(purchase.refundState.refundsDone).map(x =>
+      Amounts.parseOrThrow(x.perm.refund_amount),
     );
     const refundsPendingAmounts = Object.values(
-      purchase.refundsPending,
-    ).map(x => Amounts.parseOrThrow(x.refund_amount));
+      purchase.refundState.refundsPending,
+    ).map(x => Amounts.parseOrThrow(x.perm.refund_amount));
     const totalRefundAmount = Amounts.sum([
       ...refundsDoneAmounts,
       ...refundsPendingAmounts,
     ]).amount;
-    const refundsDoneFees = Object.values(purchase.refundsDone).map(x =>
-      Amounts.parseOrThrow(x.refund_amount),
+    const refundsDoneFees = 
Object.values(purchase.refundState.refundsDone).map(x =>
+      Amounts.parseOrThrow(x.perm.refund_amount),
     );
-    const refundsPendingFees = Object.values(purchase.refundsPending).map(x =>
-      Amounts.parseOrThrow(x.refund_amount),
+    const refundsPendingFees = 
Object.values(purchase.refundState.refundsPending).map(x =>
+      Amounts.parseOrThrow(x.perm.refund_amount),
     );
     const totalRefundFees = Amounts.sum([
       ...refundsDoneFees,
diff --git a/tsconfig.json b/tsconfig.json
index 43ccd7e2..81e529fa 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -54,6 +54,7 @@
     "src/operations/payback.ts",
     "src/operations/pending.ts",
     "src/operations/refresh.ts",
+    "src/operations/refund.ts",
     "src/operations/reserves.ts",
     "src/operations/return.ts",
     "src/operations/state.ts",

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



reply via email to

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