gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: tipping API and integration t


From: gnunet
Subject: [taler-wallet-core] branch master updated: tipping API and integration test
Date: Tue, 08 Sep 2020 14:11:07 +0200

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 b063382d tipping API and integration test
b063382d is described below

commit b063382d25d1ed8572ebe2f52bf54247379300d5
Author: Florian Dold <florian.dold@gmail.com>
AuthorDate: Tue Sep 8 17:40:47 2020 +0530

    tipping API and integration test
---
 packages/taler-integrationtests/src/harness.ts     |  67 ++++++++++++-
 .../taler-integrationtests/src/merchantApiTypes.ts |  60 ++++++++++++
 .../taler-integrationtests/src/test-tipping.ts     | 106 +++++++++++++++++++++
 packages/taler-wallet-cli/src/index.ts             |   4 +-
 packages/taler-wallet-core/src/db.ts               |   2 +-
 .../taler-wallet-core/src/operations/pending.ts    |   2 +-
 packages/taler-wallet-core/src/operations/tip.ts   |  81 +++++++---------
 packages/taler-wallet-core/src/types/dbTypes.ts    |   4 +-
 .../taler-wallet-core/src/types/notifications.ts   |   1 +
 packages/taler-wallet-core/src/types/talerTypes.ts |  17 +---
 .../taler-wallet-core/src/types/walletTypes.ts     |  56 ++++++++---
 packages/taler-wallet-core/src/wallet.ts           |  19 +++-
 packages/taler-wallet-webextension/src/wxApi.ts    |   4 -
 13 files changed, 331 insertions(+), 92 deletions(-)

diff --git a/packages/taler-integrationtests/src/harness.ts 
b/packages/taler-integrationtests/src/harness.ts
index 620b89e7..e40798b4 100644
--- a/packages/taler-integrationtests/src/harness.ts
+++ b/packages/taler-integrationtests/src/harness.ts
@@ -72,6 +72,10 @@ import {
   CoinDumpJson,
   ForceExchangeUpdateRequest,
   ForceRefreshRequest,
+  PrepareTipResult,
+  PrepareTipRequest,
+  codecForPrepareTipResult,
+  AcceptTipRequest,
 } from "taler-wallet-core";
 import { URL } from "url";
 import axios, { AxiosError } from "axios";
@@ -81,6 +85,9 @@ import {
   PostOrderRequest,
   PostOrderResponse,
   MerchantOrderPrivateStatusResponse,
+  TippingReserveStatus,
+  TipCreateConfirmation,
+  TipCreateRequest,
 } from "./merchantApiTypes";
 import { ApplyRefundResponse } from "taler-wallet-core";
 import { PendingOperationsResponse } from "taler-wallet-core";
@@ -1216,10 +1223,46 @@ export namespace MerchantPrivateApi {
     };
   }
 
-  export async function createTippingReserve(merchantService: 
MerchantServiceInterface,
-    
+  export async function createTippingReserve(
+    merchantService: MerchantServiceInterface,
+    instance: string,
     req: CreateMerchantTippingReserveRequest,
-  ): Promise<CreateMerchantTippingReserveConfirmation> {}
+  ): Promise<CreateMerchantTippingReserveConfirmation> {
+    const reqUrl = new URL(
+      `private/reserves`,
+      merchantService.makeInstanceBaseUrl(instance),
+    );
+    const resp = await axios.post(reqUrl.href, req);
+    // FIXME: validate
+    return resp.data;
+  }
+
+  export async function queryTippingReserves(
+    merchantService: MerchantServiceInterface,
+    instance: string,
+  ): Promise<TippingReserveStatus> {
+    const reqUrl = new URL(
+      `private/reserves`,
+      merchantService.makeInstanceBaseUrl(instance),
+    );
+    const resp = await axios.get(reqUrl.href);
+    // FIXME: validate
+    return resp.data;
+  }
+
+  export async function giveTip(
+    merchantService: MerchantServiceInterface,
+    instance: string,
+    req: TipCreateRequest,
+  ): Promise<TipCreateConfirmation> {
+    const reqUrl = new URL(
+      `private/tips`,
+      merchantService.makeInstanceBaseUrl(instance),
+    );
+    const resp = await axios.post(reqUrl.href, req);
+    // FIXME: validate
+    return resp.data;
+  }
 }
 
 export interface CreateMerchantTippingReserveRequest {
@@ -1238,7 +1281,7 @@ export interface CreateMerchantTippingReserveConfirmation 
{
   reserve_pub: string;
 
   // Wire account of the exchange where to transfer the funds
-  payto_url: string;
+  payto_uri: string;
 }
 
 export class MerchantService implements MerchantServiceInterface {
@@ -1594,6 +1637,22 @@ export class WalletCli {
     throw new OperationFailedError(resp.error);
   }
 
+  async prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
+    const resp = await this.apiRequest("prepareTip", req);
+    if (resp.type === "response") {
+      return codecForPrepareTipResult().decode(resp.result);
+    }
+    throw new OperationFailedError(resp.error);
+  }
+
+  async acceptTip(req: AcceptTipRequest): Promise<void> {
+    const resp = await this.apiRequest("acceptTip", req);
+    if (resp.type === "response") {
+      return;
+    }
+    throw new OperationFailedError(resp.error);
+  }
+
   async dumpCoins(): Promise<CoinDumpJson> {
     const resp = await this.apiRequest("dumpCoins", {});
     if (resp.type === "response") {
diff --git a/packages/taler-integrationtests/src/merchantApiTypes.ts 
b/packages/taler-integrationtests/src/merchantApiTypes.ts
index 550c5e90..e89e3264 100644
--- a/packages/taler-integrationtests/src/merchantApiTypes.ts
+++ b/packages/taler-integrationtests/src/merchantApiTypes.ts
@@ -223,3 +223,63 @@ export interface TransactionWireReport {
   // Public key of the coin for which we got the exchange error.
   coin_pub: CoinPublicKeyString;
 }
+
+export interface TippingReserveStatus {
+  // Array of all known reserves (possibly empty!)
+  reserves: ReserveStatusEntry[];
+}
+
+export interface ReserveStatusEntry {
+  // Public key of the reserve
+  reserve_pub: string;
+
+  // Timestamp when it was established
+  creation_time: Timestamp;
+
+  // Timestamp when it expires
+  expiration_time: Timestamp;
+
+  // Initial amount as per reserve creation call
+  merchant_initial_amount: AmountString;
+
+  // Initial amount as per exchange, 0 if exchange did
+  // not confirm reserve creation yet.
+  exchange_initial_amount: AmountString;
+
+  // Amount picked up so far.
+  pickup_amount: AmountString;
+
+  // Amount approved for tips that exceeds the pickup_amount.
+  committed_amount: AmountString;
+
+  // Is this reserve active (false if it was deleted but not purged)
+  active: boolean;
+}
+
+
+export interface TipCreateConfirmation {
+  // Unique tip identifier for the tip that was created.
+  tip_id: string;
+
+  // taler://tip URI for the tip
+  taler_tip_uri: string;
+
+  // URL that will directly trigger processing
+  // the tip when the browser is redirected to it
+  tip_status_url: string;
+
+  // when does the tip expire
+  tip_expiration: Timestamp;
+}
+
+export interface TipCreateRequest {
+  // Amount that the customer should be tipped
+  amount: AmountString;
+
+  // Justification for giving the tip
+  justification: string;
+
+  // URL that the user should be directed to after tipping,
+  // will be included in the tip_token.
+  next_url: string;
+}
\ No newline at end of file
diff --git a/packages/taler-integrationtests/src/test-tipping.ts 
b/packages/taler-integrationtests/src/test-tipping.ts
new file mode 100644
index 00000000..ddf56c0e
--- /dev/null
+++ b/packages/taler-integrationtests/src/test-tipping.ts
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNU Taler
+ (C) 2020 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
+ Foundation; either version 3, or (at your option) any later version.
+
+ 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
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import {
+  runTest,
+  GlobalTestState,
+  MerchantPrivateApi,
+  BankAccessApi,
+  BankApi,
+} from "./harness";
+import { createSimpleTestkudosEnvironment, withdrawViaBank } from "./helpers";
+
+/**
+ * Run test for basic, bank-integrated withdrawal.
+ */
+runTest(async (t: GlobalTestState) => {
+  // Set up test environment
+
+  const {
+    wallet,
+    bank,
+    exchange,
+    merchant,
+    exchangeBankAccount,
+  } = await createSimpleTestkudosEnvironment(t);
+
+  const mbu = await BankApi.createRandomBankUser(bank);
+
+  const tipReserveResp = await MerchantPrivateApi.createTippingReserve(
+    merchant,
+    "default",
+    {
+      exchange_url: exchange.baseUrl,
+      initial_balance: "TESTKUDOS:10",
+      wire_method: "x-taler-bank",
+    },
+  );
+
+  console.log("tipReserveResp:", tipReserveResp);
+
+  t.assertDeepEqual(
+    tipReserveResp.payto_uri,
+    exchangeBankAccount.accountPaytoUri,
+  );
+
+  await BankApi.adminAddIncoming(bank, {
+    amount: "TESTKUDOS:10",
+    debitAccountPayto: mbu.accountPaytoUri,
+    exchangeBankAccount,
+    reservePub: tipReserveResp.reserve_pub,
+  });
+
+  await exchange.runWirewatchOnce();
+  await merchant.stop();
+  await merchant.start();
+  await merchant.pingUntilAvailable();
+
+  const r = await MerchantPrivateApi.queryTippingReserves(merchant, "default");
+  console.log("tipping reserves:", JSON.stringify(r, undefined, 2));
+
+  t.assertTrue(r.reserves.length === 1);
+  t.assertDeepEqual(
+    r.reserves[0].exchange_initial_amount,
+    r.reserves[0].merchant_initial_amount,
+  );
+
+  const tip = await MerchantPrivateApi.giveTip(merchant, "default", {
+    amount: "TESTKUDOS:5",
+    justification: "why not?",
+    next_url: "https://example.com/after-tip";,
+  });
+
+  console.log("created tip", tip);
+
+  const ptr = await wallet.prepareTip({
+    talerTipUri: tip.taler_tip_uri,
+  });
+
+  console.log(ptr);
+
+  await wallet.acceptTip({
+    walletTipId: ptr.walletTipId,
+  });
+
+  await wallet.runUntilDone();
+
+  const bal = await wallet.getBalances();
+
+  console.log(bal);
+});
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index a19b8a8f..5a662d80 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -288,9 +288,9 @@ walletCli
           break;
         case TalerUriType.TalerTip:
           {
-            const res = await wallet.getTipStatus(uri);
+            const res = await wallet.prepareTip(uri);
             console.log("tip status", res);
-            await wallet.acceptTip(res.tipId);
+            await wallet.acceptTip(res.walletTipId);
           }
           break;
         case TalerUriType.TalerRefund:
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index b3203935..c21ff4a4 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -8,7 +8,7 @@ import { IDBFactory, IDBDatabase } from "idb-bridge";
  * with each major change.  When incrementing the major version,
  * the wallet should import data from the previous version.
  */
-const TALER_DB_NAME = "taler-walletdb-v10";
+const TALER_DB_NAME = "taler-walletdb-v11";
 
 /**
  * Current database minor version, should be incremented
diff --git a/packages/taler-wallet-core/src/operations/pending.ts 
b/packages/taler-wallet-core/src/operations/pending.ts
index 3c631eb7..91a55c70 100644
--- a/packages/taler-wallet-core/src/operations/pending.ts
+++ b/packages/taler-wallet-core/src/operations/pending.ts
@@ -368,7 +368,7 @@ async function gatherTipPending(
         type: PendingOperationType.TipPickup,
         givesLifeness: true,
         merchantBaseUrl: tip.merchantBaseUrl,
-        tipId: tip.tipId,
+        tipId: tip.walletTipId,
         merchantTipId: tip.merchantTipId,
       });
     }
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index 7949648c..6fe374bf 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -16,7 +16,7 @@
 
 import { InternalWalletState } from "./state";
 import { parseTipUri } from "../util/taleruri";
-import { TipStatus, TalerErrorDetails } from "../types/walletTypes";
+import { PrepareTipResult, TalerErrorDetails } from "../types/walletTypes";
 import {
   TipPlanchetDetail,
   codecForTipPickupGetResponse,
@@ -46,20 +46,23 @@ import { getTimestampNow } from "../util/time";
 import { readSuccessResponseJsonOrThrow } from "../util/http";
 import { URL } from "../util/url";
 import { Logger } from "../util/logging";
+import { checkDbInvariant } from "../util/invariants";
 
 const logger = new Logger("operations/tip.ts");
 
-export async function getTipStatus(
+export async function prepareTip(
   ws: InternalWalletState,
   talerTipUri: string,
-): Promise<TipStatus> {
+): Promise<PrepareTipResult> {
   const res = parseTipUri(talerTipUri);
   if (!res) {
     throw Error("invalid taler://tip URI");
   }
 
-  const tipStatusUrl = new URL("tip-pickup", res.merchantBaseUrl);
-  tipStatusUrl.searchParams.set("tip_id", res.merchantTipId);
+  const tipStatusUrl = new URL(
+    `tips/${res.merchantTipId}`,
+    res.merchantBaseUrl,
+  );
   logger.trace("checking tip status from", tipStatusUrl.href);
   const merchantResp = await ws.http.get(tipStatusUrl.href);
   const tipPickupStatus = await readSuccessResponseJsonOrThrow(
@@ -68,7 +71,7 @@ export async function getTipStatus(
   );
   logger.trace(`status ${tipPickupStatus}`);
 
-  const amount = Amounts.parseOrThrow(tipPickupStatus.amount);
+  const amount = Amounts.parseOrThrow(tipPickupStatus.tip_amount);
 
   const merchantOrigin = new URL(res.merchantBaseUrl).origin;
 
@@ -85,7 +88,7 @@ export async function getTipStatus(
       amount,
     );
 
-    const tipId = encodeCrock(getRandomBytes(32));
+    const walletTipId = encodeCrock(getRandomBytes(32));
     const selectedDenoms = await selectWithdrawalDenoms(
       ws,
       tipPickupStatus.exchange_url,
@@ -93,11 +96,11 @@ export async function getTipStatus(
     );
 
     tipRecord = {
-      tipId,
+      walletTipId: walletTipId,
       acceptedTimestamp: undefined,
       rejectedTimestamp: undefined,
       amount,
-      deadline: tipPickupStatus.stamp_expire,
+      deadline: tipPickupStatus.expiration,
       exchangeUrl: tipPickupStatus.exchange_url,
       merchantBaseUrl: res.merchantBaseUrl,
       nextUrl: undefined,
@@ -117,18 +120,13 @@ export async function getTipStatus(
     await ws.db.put(Stores.tips, tipRecord);
   }
 
-  const tipStatus: TipStatus = {
+  const tipStatus: PrepareTipResult = {
     accepted: !!tipRecord && !!tipRecord.acceptedTimestamp,
-    amount: Amounts.parseOrThrow(tipPickupStatus.amount),
-    amountLeft: Amounts.parseOrThrow(tipPickupStatus.amount_left),
-    exchangeUrl: tipPickupStatus.exchange_url,
-    nextUrl: tipPickupStatus.extra.next_url,
-    merchantOrigin: merchantOrigin,
-    merchantTipId: res.merchantTipId,
-    expirationTimestamp: tipPickupStatus.stamp_expire,
-    timestamp: tipPickupStatus.stamp_created,
-    totalFees: tipRecord.totalFees,
-    tipId: tipRecord.tipId,
+    amount: Amounts.stringify(tipPickupStatus.tip_amount),
+    exchangeBaseUrl: tipPickupStatus.exchange_url,
+    expirationTimestamp: tipPickupStatus.expiration,
+    totalFees: Amounts.stringify(tipRecord.totalFees),
+    walletTipId: tipRecord.walletTipId,
   };
 
   return tipStatus;
@@ -152,7 +150,9 @@ async function incrementTipRetry(
     t.lastError = err;
     await tx.put(Stores.tips, t);
   });
-  ws.notify({ type: NotificationType.TipOperationError });
+  if (err) {
+    ws.notify({ type: NotificationType.TipOperationError, error: err });
+  }
 }
 
 export async function processTip(
@@ -225,15 +225,8 @@ async function processTipImpl(
   }
 
   tipRecord = await ws.db.get(Stores.tips, tipId);
-  if (!tipRecord) {
-    throw Error("tip not in database");
-  }
-
-  if (!tipRecord.planchets) {
-    throw Error("invariant violated");
-  }
-
-  logger.trace("got planchets for tip!");
+  checkDbInvariant(!!tipRecord, "tip record should be in database");
+  checkDbInvariant(!!tipRecord.planchets, "tip record should have planchets");
 
   // Planchets in the form that the merchant expects
   const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map((p) => 
({
@@ -241,23 +234,17 @@ async function processTipImpl(
     denom_pub_hash: p.denomPubHash,
   }));
 
-  let merchantResp;
-
-  const tipStatusUrl = new URL("tip-pickup", tipRecord.merchantBaseUrl);
-
-  try {
-    const req = { planchets: planchetsDetail, tip_id: tipRecord.merchantTipId 
};
-    merchantResp = await ws.http.postJson(tipStatusUrl.href, req);
-    if (merchantResp.status !== 200) {
-      throw Error(`unexpected status ${merchantResp.status} for tip-pickup`);
-    }
-    logger.trace("got merchant resp:", merchantResp);
-  } catch (e) {
-    logger.warn("tipping failed", e);
-    throw e;
-  }
+  const tipStatusUrl = new URL(
+    `/tips/${tipRecord.merchantTipId}/pickup`,
+    tipRecord.merchantBaseUrl,
+  );
 
-  const response = codecForTipResponse().decode(await merchantResp.json());
+  const req = { planchets: planchetsDetail };
+  const merchantResp = await ws.http.postJson(tipStatusUrl.href, req);
+  const response = await readSuccessResponseJsonOrThrow(
+    merchantResp,
+    codecForTipResponse(),
+  );
 
   if (response.reserve_sigs.length !== tipRecord.planchets.length) {
     throw Error("number of tip responses does not match requested planchets");
@@ -293,7 +280,7 @@ async function processTipImpl(
     exchangeBaseUrl: tipRecord.exchangeUrl,
     source: {
       type: WithdrawalSourceType.Tip,
-      tipId: tipRecord.tipId,
+      tipId: tipRecord.walletTipId,
     },
     timestampStart: getTimestampNow(),
     withdrawalGroupId: withdrawalGroupId,
diff --git a/packages/taler-wallet-core/src/types/dbTypes.ts 
b/packages/taler-wallet-core/src/types/dbTypes.ts
index 0ee41a6a..4e2ba1bb 100644
--- a/packages/taler-wallet-core/src/types/dbTypes.ts
+++ b/packages/taler-wallet-core/src/types/dbTypes.ts
@@ -986,7 +986,7 @@ export interface TipRecord {
   /**
    * Tip ID chosen by the wallet.
    */
-  tipId: string;
+  walletTipId: string;
 
   /**
    * The merchant's identifier for this tip.
@@ -1760,7 +1760,7 @@ class ReserveHistoryStore extends 
Store<ReserveHistoryRecord> {
 
 class TipsStore extends Store<TipRecord> {
   constructor() {
-    super("tips", { keyPath: "tipId" });
+    super("tips", { keyPath: "walletTipId" });
   }
 }
 
diff --git a/packages/taler-wallet-core/src/types/notifications.ts 
b/packages/taler-wallet-core/src/types/notifications.ts
index 7a51f0d8..e1b9a7af 100644
--- a/packages/taler-wallet-core/src/types/notifications.ts
+++ b/packages/taler-wallet-core/src/types/notifications.ts
@@ -186,6 +186,7 @@ export interface ProposalOperationErrorNotification {
 
 export interface TipOperationErrorNotification {
   type: NotificationType.TipOperationError;
+  error: TalerErrorDetails;
 }
 
 export interface WithdrawOperationErrorNotification {
diff --git a/packages/taler-wallet-core/src/types/talerTypes.ts 
b/packages/taler-wallet-core/src/types/talerTypes.ts
index c944f156..52dc4cb6 100644
--- a/packages/taler-wallet-core/src/types/talerTypes.ts
+++ b/packages/taler-wallet-core/src/types/talerTypes.ts
@@ -773,17 +773,11 @@ export class WithdrawOperationStatusResponse {
  * Response from the merchant.
  */
 export class TipPickupGetResponse {
-  extra: any;
-
-  amount: string;
-
-  amount_left: string;
+  tip_amount: string;
 
   exchange_url: string;
 
-  stamp_expire: Timestamp;
-
-  stamp_created: Timestamp;
+  expiration: Timestamp;
 }
 
 export class WithdrawResponse {
@@ -1261,12 +1255,9 @@ export const codecForWithdrawOperationStatusResponse = 
(): Codec<
 
 export const codecForTipPickupGetResponse = (): Codec<TipPickupGetResponse> =>
   buildCodecForObject<TipPickupGetResponse>()
-    .property("extra", codecForAny())
-    .property("amount", codecForString())
-    .property("amount_left", codecForString())
+    .property("tip_amount", codecForString())
     .property("exchange_url", codecForString())
-    .property("stamp_expire", codecForTimestamp)
-    .property("stamp_created", codecForTimestamp)
+    .property("expiration", codecForTimestamp)
     .build("TipPickupGetResponse");
 
 export const codecForRecoupConfirmation = (): Codec<RecoupConfirmation> =>
diff --git a/packages/taler-wallet-core/src/types/walletTypes.ts 
b/packages/taler-wallet-core/src/types/walletTypes.ts
index 82f29c39..fb049caf 100644
--- a/packages/taler-wallet-core/src/types/walletTypes.ts
+++ b/packages/taler-wallet-core/src/types/walletTypes.ts
@@ -38,7 +38,7 @@ import {
   ExchangeWireInfo,
   DenominationSelectionInfo,
 } from "./dbTypes";
-import { Timestamp } from "../util/time";
+import { Timestamp, codecForTimestamp } from "../util/time";
 import {
   buildCodecForObject,
   codecForString,
@@ -348,23 +348,33 @@ export class ReturnCoinsRequest {
   static checked: (obj: any) => ReturnCoinsRequest;
 }
 
-/**
- * Status of processing a tip.
- */
-export interface TipStatus {
+export interface PrepareTipResult {
+  /**
+   * Unique ID for the tip assigned by the wallet.
+   * Typically different from the merchant-generated tip ID.
+   */
+  walletTipId: string;
+
+  /**
+   * Has the tip already been accepted?
+   */
   accepted: boolean;
-  amount: AmountJson;
-  amountLeft: AmountJson;
-  nextUrl: string;
-  exchangeUrl: string;
-  tipId: string;
-  merchantTipId: string;
-  merchantOrigin: string;
+  amount: AmountString;
+  totalFees: AmountString;
+  exchangeBaseUrl: string;
   expirationTimestamp: Timestamp;
-  timestamp: Timestamp;
-  totalFees: AmountJson;
 }
 
+export const codecForPrepareTipResult = (): Codec<PrepareTipResult> =>
+  buildCodecForObject<PrepareTipResult>()
+     .property("accepted", codecForBoolean())
+     .property("amount", codecForAmountString())
+     .property("totalFees", codecForAmountString())
+     .property("exchangeBaseUrl", codecForString())
+     .property("expirationTimestamp", codecForTimestamp)
+     .property("walletTipId", codecForString())
+    .build("PrepareTipResult");
+
 export interface BenchmarkResult {
   time: { [s: string]: number };
   repetitions: number;
@@ -903,3 +913,21 @@ export const codecForForceRefreshRequest = (): 
Codec<ForceRefreshRequest> =>
   buildCodecForObject<ForceRefreshRequest>()
     .property("coinPubList", codecForList(codecForString()))
     .build("ForceRefreshRequest");
+
+export interface PrepareTipRequest {
+  talerTipUri: string;
+}
+
+export const codecForPrepareTipRequest = (): Codec<PrepareTipRequest> =>
+  buildCodecForObject<PrepareTipRequest>()
+    .property("talerTipUri", codecForString())
+    .build("PrepareTipRequest");
+
+export interface AcceptTipRequest {
+  walletTipId: string;
+}
+
+export const codecForAcceptTipRequest = (): Codec<AcceptTipRequest> =>
+  buildCodecForObject<AcceptTipRequest>()
+    .property("walletTipId", codecForString())
+    .build("AcceptTipRequest");
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 9666665a..0507ac8b 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -59,7 +59,6 @@ import {
   ConfirmPayResult,
   ReturnCoinsRequest,
   SenderWireInfos,
-  TipStatus,
   PreparePayResult,
   AcceptWithdrawalResponse,
   PurchaseDetails,
@@ -93,6 +92,9 @@ import {
   codecForSetCoinSuspendedRequest,
   codecForForceExchangeUpdateRequest,
   codecForForceRefreshRequest,
+  PrepareTipResult,
+  codecForPrepareTipRequest,
+  codecForAcceptTipRequest,
 } from "./types/walletTypes";
 import { Logger } from "./util/logging";
 
@@ -121,7 +123,7 @@ import {
 import { processWithdrawGroup } from "./operations/withdraw";
 import { getPendingOperations } from "./operations/pending";
 import { getBalances } from "./operations/balance";
-import { acceptTip, getTipStatus, processTip } from "./operations/tip";
+import { acceptTip, prepareTip, processTip } from "./operations/tip";
 import { TimerGroup } from "./util/timer";
 import { AsyncCondition } from "./util/promiseUtils";
 import { AsyncOpMemoSingle } from "./util/asyncMemo";
@@ -769,8 +771,8 @@ export class Wallet {
     }
   }
 
-  async getTipStatus(talerTipUri: string): Promise<TipStatus> {
-    return getTipStatus(this.ws, talerTipUri);
+  async prepareTip(talerTipUri: string): Promise<PrepareTipResult> {
+    return prepareTip(this.ws, talerTipUri);
   }
 
   async abortFailedPayment(contractTermsHash: string): Promise<void> {
@@ -1096,6 +1098,15 @@ export class Wallet {
           refreshGroupId,
         };
       }
+      case "prepareTip": {
+        const req = codecForPrepareTipRequest().decode(payload);
+        return await this.prepareTip(req.talerTipUri);
+      }
+      case "acceptTip": {
+        const req = codecForAcceptTipRequest().decode(payload);
+        await this.acceptTip(req.walletTipId);
+        return {};
+      }
     }
     throw OperationFailedError.fromCode(
       TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 947b63ce..9bc4a08e 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -22,12 +22,8 @@
  * Imports.
  */
 import {
-  AmountJson,
   ConfirmPayResult,
   BalancesResponse,
-  PurchaseDetails,
-  TipStatus,
-  BenchmarkResult,
   PreparePayResult,
   AcceptWithdrawalResponse,
   WalletDiagnostics,

-- 
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]