gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: deposit from payto


From: gnunet
Subject: [taler-wallet-core] branch master updated: deposit from payto
Date: Tue, 03 May 2022 05:16:12 +0200

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 dc842eab deposit from payto
dc842eab is described below

commit dc842eab6b7a3b2e891ee89a325ec73e04d3be95
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue May 3 00:16:03 2022 -0300

    deposit from payto
---
 packages/taler-util/src/walletTypes.ts             |  17 +++
 .../taler-wallet-core/src/operations/deposits.ts   | 104 ++++++++++++++
 packages/taler-wallet-core/src/wallet.ts           |   6 +
 .../src/NavigationBar.tsx                          |   1 +
 .../src/components/Part.tsx                        |  43 +++++-
 .../src/cta/Deposit.stories.tsx                    |  13 +-
 .../src/cta/Deposit.test.ts                        |  92 ++++++++++++
 .../taler-wallet-webextension/src/cta/Deposit.tsx  | 158 +++++++++++++++++++--
 .../src/wallet/Application.tsx                     |   2 +
 .../src/wallet/Transaction.tsx                     |   6 +-
 packages/taler-wallet-webextension/src/wxApi.ts    |  12 ++
 11 files changed, 435 insertions(+), 19 deletions(-)

diff --git a/packages/taler-util/src/walletTypes.ts 
b/packages/taler-util/src/walletTypes.ts
index c6367f8e..d8696377 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -1070,6 +1070,23 @@ export const codecForGetFeeForDeposit = (): 
Codec<GetFeeForDepositRequest> =>
     .property("depositPaytoUri", codecForString())
     .build("GetFeeForDepositRequest");
 
+export interface PrepareDepositRequest {
+  depositPaytoUri: string;
+  amount: AmountString;
+
+}
+export const codecForPrepareDepositRequest =
+  (): Codec<PrepareDepositRequest> =>
+    buildCodecForObject<PrepareDepositRequest>()
+      .property("amount", codecForAmountString())
+      .property("depositPaytoUri", codecForString())
+      .build("PrepareDepositRequest");
+
+export interface PrepareDepositResponse {
+  totalDepositCost: AmountJson;
+  effectiveDepositAmount: AmountJson;
+}
+
 export const codecForCreateDepositGroupRequest =
   (): Codec<CreateDepositGroupRequest> =>
     buildCodecForObject<CreateDepositGroupRequest>()
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 075d9d73..15c0e311 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -35,6 +35,8 @@ import {
   Logger,
   NotificationType,
   parsePaytoUri,
+  PrepareDepositRequest,
+  PrepareDepositResponse,
   TalerErrorDetail,
   TalerProtocolTimestamp,
   TrackDepositGroupRequest,
@@ -367,6 +369,108 @@ export async function getFeeForDeposit(
   );
 }
 
+export async function prepareDepositGroup(
+  ws: InternalWalletState,
+  req: PrepareDepositRequest,
+): Promise<PrepareDepositResponse> {
+  const p = parsePaytoUri(req.depositPaytoUri);
+  if (!p) {
+    throw Error("invalid payto URI");
+  }
+  const amount = Amounts.parseOrThrow(req.amount);
+
+
+  const exchangeInfos: { url: string; master_pub: string }[] = [];
+
+  await ws.db
+    .mktx((x) => ({
+      exchanges: x.exchanges,
+      exchangeDetails: x.exchangeDetails,
+    }))
+    .runReadOnly(async (tx) => {
+      const allExchanges = await tx.exchanges.iter().toArray();
+      for (const e of allExchanges) {
+        const details = await getExchangeDetails(tx, e.baseUrl);
+        if (!details || amount.currency !== details.currency) {
+          continue;
+        }
+        exchangeInfos.push({
+          master_pub: details.masterPublicKey,
+          url: e.baseUrl,
+        });
+      }
+    });
+
+  const now = AbsoluteTime.now();
+  const nowRounded = AbsoluteTime.toTimestamp(now);
+  const contractTerms: ContractTerms = {
+    auditors: [],
+    exchanges: exchangeInfos,
+    amount: req.amount,
+    max_fee: Amounts.stringify(amount),
+    max_wire_fee: Amounts.stringify(amount),
+    wire_method: p.targetType,
+    timestamp: nowRounded,
+    merchant_base_url: "",
+    summary: "",
+    nonce: "",
+    wire_transfer_deadline: nowRounded,
+    order_id: "",
+    h_wire: "",
+    pay_deadline: AbsoluteTime.toTimestamp(
+      AbsoluteTime.addDuration(now, durationFromSpec({ hours: 1 })),
+    ),
+    merchant: {
+      name: "(wallet)",
+    },
+    merchant_pub: "",
+    refund_deadline: TalerProtocolTimestamp.zero(),
+  };
+
+  const { h: contractTermsHash } = await ws.cryptoApi.hashString({
+    str: canonicalJson(contractTerms),
+  });
+
+  const contractData = extractContractData(
+    contractTerms,
+    contractTermsHash,
+    "",
+  );
+
+  const candidates = await getCandidatePayCoins(ws, {
+    allowedAuditors: contractData.allowedAuditors,
+    allowedExchanges: contractData.allowedExchanges,
+    amount: contractData.amount,
+    maxDepositFee: contractData.maxDepositFee,
+    maxWireFee: contractData.maxWireFee,
+    timestamp: contractData.timestamp,
+    wireFeeAmortization: contractData.wireFeeAmortization,
+    wireMethod: contractData.wireMethod,
+  });
+
+  const payCoinSel = selectPayCoins({
+    candidates,
+    contractTermsAmount: contractData.amount,
+    depositFeeLimit: contractData.maxDepositFee,
+    wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
+    wireFeeLimit: contractData.maxWireFee,
+    prevPayCoins: [],
+  });
+
+  if (!payCoinSel) {
+    throw Error("insufficient funds");
+  }
+
+  const totalDepositCost = await getTotalPaymentCost(ws, payCoinSel);
+
+  const effectiveDepositAmount = await getEffectiveDepositAmount(
+    ws,
+    p.targetType,
+    payCoinSel,
+  );
+
+  return { totalDepositCost, effectiveDepositAmount }
+}
 export async function createDepositGroup(
   ws: InternalWalletState,
   req: CreateDepositGroupRequest,
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 7760c0be..7c917c41 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -46,6 +46,7 @@ import {
   codecForImportDbRequest,
   codecForIntegrationTestArgs,
   codecForListKnownBankAccounts,
+  codecForPrepareDepositRequest,
   codecForPreparePayRequest, codecForPrepareRefundRequest, 
codecForPrepareTipRequest,
   codecForRetryTransactionRequest,
   codecForSetCoinSuspendedRequest,
@@ -114,6 +115,7 @@ import { getBalances } from "./operations/balance.js";
 import {
   createDepositGroup,
   getFeeForDeposit,
+  prepareDepositGroup,
   processDepositGroup,
   trackDepositGroup
 } from "./operations/deposits.js";
@@ -944,6 +946,10 @@ async function dispatchRequestInternal(
       const req = codecForGetFeeForDeposit().decode(payload);
       return await getFeeForDeposit(ws, req);
     }
+    case "prepareDeposit": {
+      const req = codecForPrepareDepositRequest().decode(payload);
+      return await prepareDepositGroup(ws, req);
+    }
     case "createDepositGroup": {
       const req = codecForCreateDepositGroupRequest().decode(payload);
       return await createDepositGroup(ws, req);
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx 
b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index df779cae..58783a08 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -63,6 +63,7 @@ export enum Pages {
   cta_refund = "/cta/refund",
   cta_tips = "/cta/tip",
   cta_withdraw = "/cta/withdraw",
+  cta_deposit = "/cta/deposit",
 }
 
 export function PopupNavBar({ path = "" }: { path?: string }): VNode {
diff --git a/packages/taler-wallet-webextension/src/components/Part.tsx 
b/packages/taler-wallet-webextension/src/components/Part.tsx
index d1683b20..21c0f65d 100644
--- a/packages/taler-wallet-webextension/src/components/Part.tsx
+++ b/packages/taler-wallet-webextension/src/components/Part.tsx
@@ -13,7 +13,8 @@
  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/>
  */
-import { h, VNode } from "preact";
+import { PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
 import { ExtraLargeText, LargeText, SmallLightText } from "./styled/index.js";
 
 export type Kind = "positive" | "negative" | "neutral";
@@ -39,3 +40,43 @@ export function Part({ text, title, kind, big }: Props): 
VNode {
     </div>
   );
 }
+
+interface PropsPayto {
+  payto: PaytoUri;
+  kind: Kind;
+  big?: boolean;
+}
+export function PartPayto({ payto, kind, big }: PropsPayto): VNode {
+  const Text = big ? ExtraLargeText : LargeText;
+  let text: string | undefined = undefined;
+  let title = "";
+  if (payto.isKnown) {
+    if (payto.targetType === "x-taler-bank") {
+      text = payto.account;
+      title = "Bank account";
+    } else if (payto.targetType === "bitcoin") {
+      text = payto.targetPath;
+      title = "Bitcoin addr";
+    } else if (payto.targetType === "iban") {
+      text = payto.targetPath;
+      title = "IBAN";
+    }
+  }
+  if (!text) {
+    text = stringifyPaytoUri(payto);
+    title = "Payto URI";
+  }
+  return (
+    <div style={{ margin: "1em" }}>
+      <SmallLightText style={{ margin: ".5em" }}>{title}</SmallLightText>
+      <Text
+        style={{
+          color:
+            kind == "positive" ? "green" : kind == "negative" ? "red" : 
"black",
+        }}
+      >
+        {text}
+      </Text>
+    </div>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
index 6432d532..7356bb4e 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
@@ -19,7 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { ContractTerms, PreparePayResultType } from "@gnu-taler/taler-util";
+import { Amounts } from "@gnu-taler/taler-util";
 import { createExample } from "../test-utils.js";
 import { View as TestedComponent } from "./Deposit.js";
 
@@ -29,6 +29,13 @@ export default {
   argTypes: {},
 };
 
-export const Simple = createExample(TestedComponent, {
-  state: { status: "ready" },
+export const Ready = createExample(TestedComponent, {
+  state: {
+    status: "ready",
+    confirm: {},
+    cost: Amounts.parseOrThrow("EUR:1.2"),
+    effective: Amounts.parseOrThrow("EUR:1"),
+    fee: Amounts.parseOrThrow("EUR:0.2"),
+    hook: undefined,
+  },
 });
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.test.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit.test.ts
new file mode 100644
index 00000000..16e7961c
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/Deposit.test.ts
@@ -0,0 +1,92 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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/>
+ */
+
+/**
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+
+import { Amounts, PrepareDepositResponse } from "@gnu-taler/taler-util";
+import { expect } from "chai";
+import { mountHook } from "../test-utils.js";
+import { useComponentState } from "./Deposit.jsx";
+
+describe("Deposit CTA states", () => {
+  it("should tell the user that the URI is missing", async () => {
+    const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = 
mountHook(() =>
+      useComponentState(undefined, undefined, {
+        prepareRefund: async () => ({}),
+        applyRefund: async () => ({}),
+        onUpdateNotification: async () => ({})
+      } as any),
+    );
+
+    {
+      const { status, hook } = getLastResultOrThrow()
+      expect(status).equals('loading')
+      expect(hook).undefined;
+    }
+
+    await waitNextUpdate()
+
+    {
+      const { status, hook } = getLastResultOrThrow()
+
+      expect(status).equals('loading')
+      if (!hook) expect.fail();
+      if (!hook.hasError) expect.fail();
+      if (hook.operational) expect.fail();
+      expect(hook.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
+    }
+
+    await assertNoPendingUpdate()
+  });
+
+  it("should be ready after loading", async () => {
+    const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = 
mountHook(() =>
+      useComponentState("payto://refund/asdasdas", "EUR:1", {
+        prepareDeposit: async () => ({
+          effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
+          totalDepositCost: Amounts.parseOrThrow("EUR:1.2")
+        } as PrepareDepositResponse as any),
+        createDepositGroup: async () => ({}),
+      } as any),
+    );
+
+    {
+      const { status, hook } = getLastResultOrThrow()
+      expect(status).equals('loading')
+      expect(hook).undefined;
+    }
+
+    await waitNextUpdate()
+
+    {
+      const state = getLastResultOrThrow()
+
+      if (state.status !== 'ready') expect.fail();
+      if (state.hook) expect.fail();
+      expect(state.confirm.onClick).not.undefined;
+      expect(state.cost).deep.eq(Amounts.parseOrThrow("EUR:1.2"));
+      expect(state.fee).deep.eq(Amounts.parseOrThrow("EUR:0.2"));
+      expect(state.effective).deep.eq(Amounts.parseOrThrow("EUR:1"));
+    }
+
+    await assertNoPendingUpdate()
+
+  });
+
+});
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit.tsx
index 529da11b..2fc7cbc4 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit.tsx
@@ -24,48 +24,120 @@
  * Imports.
  */
 
+import {
+  AmountJson,
+  Amounts,
+  AmountString,
+  CreateDepositGroupResponse,
+} from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Amount } from "../components/Amount.js";
 import { Loading } from "../components/Loading.js";
 import { LoadingError } from "../components/LoadingError.js";
 import { LogoHeader } from "../components/LogoHeader.js";
-import { SubTitle, WalletAction } from "../components/styled/index.js";
+import { Part } from "../components/Part.js";
+import {
+  ButtonSuccess,
+  SubTitle,
+  WalletAction,
+} from "../components/styled/index.js";
 import { useTranslationContext } from "../context/translation.js";
-import { HookError } from "../hooks/useAsyncAsHook.js";
+import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
+import { ButtonHandler } from "../mui/handlers.js";
+import * as wxApi from "../wxApi.js";
 
 interface Props {
   talerDepositUri?: string;
+  amount: AmountString;
   goBack: () => void;
 }
 
-type State = Loading | Ready;
+type State = Loading | Ready | Completed;
 interface Loading {
   status: "loading";
   hook: HookError | undefined;
 }
 interface Ready {
   status: "ready";
+  hook: undefined;
+  fee: AmountJson;
+  cost: AmountJson;
+  effective: AmountJson;
+  confirm: ButtonHandler;
 }
+interface Completed {
+  status: "completed";
+  hook: undefined;
+}
+
+export function useComponentState(
+  talerDepositUri: string | undefined,
+  amountStr: AmountString | undefined,
+  api: typeof wxApi,
+): State {
+  const [result, setResult] = useState<CreateDepositGroupResponse | undefined>(
+    undefined,
+  );
+
+  const info = useAsyncAsHook(async () => {
+    if (!talerDepositUri) throw Error("ERROR_NO-URI-FOR-DEPOSIT");
+    if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
+    const amount = Amounts.parse(amountStr);
+    if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
+    const deposit = await api.prepareDeposit(
+      talerDepositUri,
+      Amounts.stringify(amount),
+    );
+    return { deposit, uri: talerDepositUri, amount };
+  });
+
+  if (!info || info.hasError) {
+    return {
+      status: "loading",
+      hook: info,
+    };
+  }
+
+  const { deposit, uri, amount } = info.response;
+  async function doDeposit(): Promise<void> {
+    const resp = await api.createDepositGroup(uri, Amounts.stringify(amount));
+    setResult(resp);
+  }
+
+  if (result !== undefined) {
+    return {
+      status: "completed",
+      hook: undefined,
+    };
+  }
 
-function useComponentState(uri: string | undefined): State {
   return {
-    status: "loading",
+    status: "ready",
     hook: undefined,
+    confirm: {
+      onClick: doDeposit,
+    },
+    fee: Amounts.sub(deposit.totalDepositCost, deposit.effectiveDepositAmount)
+      .amount,
+    cost: deposit.totalDepositCost,
+    effective: deposit.effectiveDepositAmount,
   };
 }
 
-export function DepositPage({ talerDepositUri, goBack }: Props): VNode {
+export function DepositPage({ talerDepositUri, amount, goBack }: Props): VNode 
{
   const { i18n } = useTranslationContext();
 
-  const state = useComponentState(talerDepositUri);
-  if (state.status === "loading") {
-    if (!state.hook) return <Loading />;
+  const state = useComponentState(talerDepositUri, amount, wxApi);
+
+  if (!talerDepositUri) {
     return (
-      <LoadingError
-        title={<i18n.Translate>Could not load pay status</i18n.Translate>}
-        error={state.hook}
-      />
+      <span>
+        <i18n.Translate>missing taler deposit uri</i18n.Translate>
+      </span>
     );
   }
+
   return <View state={state} />;
 }
 
@@ -75,13 +147,71 @@ export interface ViewProps {
 export function View({ state }: ViewProps): VNode {
   const { i18n } = useTranslationContext();
 
+  if (state.status === "loading") {
+    if (!state.hook) return <Loading />;
+    return (
+      <LoadingError
+        title={<i18n.Translate>Could not load deposit status</i18n.Translate>}
+        error={state.hook}
+      />
+    );
+  }
+
+  if (state.status === "completed") {
+    return (
+      <WalletAction>
+        <LogoHeader />
+
+        <SubTitle>
+          <i18n.Translate>Digital cash deposit</i18n.Translate>
+        </SubTitle>
+        <section>
+          <p>
+            <i18n.Translate>deposit completed</i18n.Translate>
+          </p>
+        </section>
+      </WalletAction>
+    );
+  }
+
   return (
     <WalletAction>
       <LogoHeader />
 
       <SubTitle>
-        <i18n.Translate>Digital cash refund</i18n.Translate>
+        <i18n.Translate>Digital cash deposit</i18n.Translate>
       </SubTitle>
+      <section>
+        {Amounts.isNonZero(state.cost) && (
+          <Part
+            big
+            title={<i18n.Translate>Cost</i18n.Translate>}
+            text={<Amount value={state.cost} />}
+            kind="negative"
+          />
+        )}
+        {Amounts.isNonZero(state.fee) && (
+          <Part
+            big
+            title={<i18n.Translate>Fee</i18n.Translate>}
+            text={<Amount value={state.fee} />}
+            kind="negative"
+          />
+        )}
+        <Part
+          big
+          title={<i18n.Translate>To be received</i18n.Translate>}
+          text={<Amount value={state.effective} />}
+          kind="positive"
+        />
+      </section>
+      <section>
+        <ButtonSuccess upperCased onClick={state.confirm.onClick}>
+          <i18n.Translate>
+            Deposit {<Amount value={state.effective} />}
+          </i18n.Translate>
+        </ButtonSuccess>
+      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index a5197d5b..6a7f62c6 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -38,6 +38,7 @@ import { PayPage } from "../cta/Pay.js";
 import { RefundPage } from "../cta/Refund.js";
 import { TipPage } from "../cta/Tip.js";
 import { WithdrawPage } from "../cta/Withdraw.js";
+import { DepositPage as DepositPageCTA } from "../cta/Deposit.js";
 import { Pages, WalletNavBar } from "../NavigationBar.js";
 import { DeveloperPage } from "./DeveloperPage.js";
 import { BackupPage } from "./BackupPage.js";
@@ -232,6 +233,7 @@ export function Application(): VNode {
               <Route path={Pages.cta_refund} component={RefundPage} />
               <Route path={Pages.cta_tips} component={TipPage} />
               <Route path={Pages.cta_withdraw} component={WithdrawPage} />
+              <Route path={Pages.cta_deposit} component={DepositPageCTA} />
 
               {/**
                * NOT FOUND
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 6f7c208d..bcf6114a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -19,6 +19,7 @@ import {
   Amounts,
   NotificationType,
   parsePaytoUri,
+  parsePayUri,
   Transaction,
   TransactionType,
   WithdrawalType,
@@ -32,13 +33,14 @@ import { BankDetailsByPaytoType } from 
"../components/BankDetailsByPaytoType.js"
 import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js";
 import { Loading } from "../components/Loading.js";
 import { LoadingError } from "../components/LoadingError.js";
-import { Part } from "../components/Part.js";
+import { Part, PartPayto } from "../components/Part.js";
 import {
   Button,
   ButtonDestructive,
   ButtonPrimary,
   CenteredDialog,
   InfoBox,
+  LargeText,
   ListOfProducts,
   Overlay,
   RowBorderGray,
@@ -428,6 +430,7 @@ export function TransactionView({
       Amounts.parseOrThrow(transaction.amountEffective),
       Amounts.parseOrThrow(transaction.amountRaw),
     ).amount;
+    const payto = parsePaytoUri(transaction.targetPaytoUri);
     return (
       <TransactionTemplate>
         <SubTitle>
@@ -456,6 +459,7 @@ export function TransactionView({
           text={<Amount value={fee} />}
           kind="negative"
         />
+        {payto && <PartPayto big payto={payto} kind="neutral" />}
       </TransactionTemplate>
     );
   }
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index d2e90305..b4882664 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -43,6 +43,8 @@ import {
   GetWithdrawalDetailsForUriRequest,
   KnownBankAccounts,
   NotificationType,
+  PrepareDepositRequest,
+  PrepareDepositResponse,
   PreparePayResult,
   PrepareRefundRequest,
   PrepareRefundResult,
@@ -160,6 +162,16 @@ export function getFeeForDeposit(
   } as GetFeeForDepositRequest);
 }
 
+export function prepareDeposit(
+  depositPaytoUri: string,
+  amount: AmountString,
+): Promise<PrepareDepositResponse> {
+  return callBackend("prepareDeposit", {
+    depositPaytoUri,
+    amount,
+  } as PrepareDepositRequest);
+}
+
 export function createDepositGroup(
   depositPaytoUri: string,
   amount: AmountString,

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