gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (7033150c8 -> ca076e5ea)


From: gnunet
Subject: [taler-wallet-core] branch master updated (7033150c8 -> ca076e5ea)
Date: Mon, 13 Nov 2023 19:34:01 +0100

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

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

    from 7033150c8 harness: support tests with multiple exchanges
     new 23e567b6a remove icon, fix dates
     new ca076e5ea fix new libeufin api

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/demobank-ui/src/hooks/circuit.ts          |  30 ++--
 .../demobank-ui/src/pages/ShowAccountDetails.tsx   |   2 +-
 packages/demobank-ui/src/pages/admin/AdminHome.tsx |  14 +-
 .../src/pages/business/CreateCashout.tsx           |  52 +++---
 .../src/pages/business/ShowCashoutDetails.tsx      |  30 +++-
 packages/demobank-ui/src/utils.ts                  |   1 -
 .../taler-harness/src/http-client/bank-core.ts     |  21 ++-
 packages/taler-util/src/http-client/bank-core.ts   |  89 ++++++++--
 packages/taler-util/src/http-client/types.ts       | 185 +++++++++++++--------
 .../src/wallet/DeveloperPage.tsx                   |   6 +-
 .../src/wallet/History.tsx                         |  15 +-
 .../taler-wallet-webextension/static/img/icon.png  | Bin 830 -> 0 bytes
 .../taler-wallet-webextension/static/wallet.html   |  67 ++++----
 13 files changed, 323 insertions(+), 189 deletions(-)
 delete mode 100644 packages/taler-wallet-webextension/static/img/icon.png

diff --git a/packages/demobank-ui/src/hooks/circuit.ts 
b/packages/demobank-ui/src/hooks/circuit.ts
index 845f37822..44edb4f8a 100644
--- a/packages/demobank-ui/src/hooks/circuit.ts
+++ b/packages/demobank-ui/src/hooks/circuit.ts
@@ -266,26 +266,34 @@ export function useLastMonitorInfo(time: Date, timeframe: 
TalerCorebankApi.Monit
     const current: TalerCoreBankResultByMethod<"getMonitor"> = {
       type: "ok" as const,
       body: {
-        type: "with-cashout" as const,
+        type: "with-conversions" as const,
         cashinCount: 1,
-        cashinExternalVolume: "LOCAL:1234" as AmountString,
+        cashinFiatVolume: "LOCAL:2345" as AmountString,
+        cashinRegionalVolume: "LOCAL:2345" as AmountString,
         cashoutCount: 2,
-        cashoutExternalVolume: "LOCAL:2345" as AmountString,
-        talerPayoutCount: 3,
-        talerPayoutInternalVolume: "LOCAL:3456" as AmountString,
+        cashoutFiatVolume: "LOCAL:2345" as AmountString,
+        cashoutRegionalVolume: "LOCAL:2345" as AmountString,
+        talerInCount: 1,
+        talerInVolume: "LOCAL:2345" as AmountString,
+        talerOutCount: 2,
+        talerOutVolume: "LOCAL:2345" as AmountString,
       }
     }
 
-    const previous = {
+    const previous: TalerCoreBankResultByMethod<"getMonitor">  = {
       type: "ok" as const,
       body: {
-        type: "with-cashout" as const,
+        type: "with-conversions" as const,
         cashinCount: 1,
-        cashinExternalVolume: "LOCAL:2345" as AmountString,
+        cashinFiatVolume: "LOCAL:2345" as AmountString,
+        cashinRegionalVolume: "LOCAL:2345" as AmountString,
         cashoutCount: 2,
-        cashoutExternalVolume: "LOCAL:2345" as AmountString,
-        talerPayoutCount: 3,
-        talerPayoutInternalVolume: "LOCAL:3456" as AmountString,
+        cashoutFiatVolume: "LOCAL:2345" as AmountString,
+        cashoutRegionalVolume: "LOCAL:2345" as AmountString,
+        talerInCount: 1,
+        talerInVolume: "LOCAL:2345" as AmountString,
+        talerOutCount: 2,
+        talerOutVolume: "LOCAL:2345" as AmountString,
       }
 
     }
diff --git a/packages/demobank-ui/src/pages/ShowAccountDetails.tsx 
b/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
index 2e00fdbba..a88a90499 100644
--- a/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
+++ b/packages/demobank-ui/src/pages/ShowAccountDetails.tsx
@@ -58,7 +58,7 @@ export function ShowAccountDetails({
           email: submitAccount.contact_data?.email,
           phone: submitAccount.contact_data?.phone,
         }),
-        is_exchange: false,
+        is_taler_exchange: false,
         name: submitAccount.name,
       });
 
diff --git a/packages/demobank-ui/src/pages/admin/AdminHome.tsx 
b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
index 9bc2ee571..a89b4afca 100644
--- a/packages/demobank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
@@ -124,15 +124,15 @@ function Metrics(): VNode {
     </div>
     <dl class="mt-5 grid grid-cols-1 divide-y divide-gray-200 overflow-hidden 
rounded-lg bg-white shadow-lg md:grid-cols-3 md:divide-x md:divide-y-0">
 
-      {resp.current.body.type !== "with-cashout" || resp.previous.body.type 
!== "with-cashout" ? undefined :
+      {resp.current.body.type !== "with-conversions" || 
resp.previous.body.type !== "with-conversions" ? undefined :
         <Fragment>
           <div class="px-4 py-5 sm:p-6">
             <dt class="text-base font-normal text-gray-900">
               <i18n.Translate>Cashin</i18n.Translate>
             </dt>
             <MetricValue
-              current={resp.current.body.cashinExternalVolume}
-              previous={resp.previous.body.cashinExternalVolume}
+              current={resp.current.body.cashinFiatVolume}
+              previous={resp.previous.body.cashinFiatVolume}
             />
           </div>
           <div class="px-4 py-5 sm:p-6">
@@ -140,8 +140,8 @@ function Metrics(): VNode {
               <i18n.Translate>Cashout</i18n.Translate>
             </dt>
             <MetricValue
-              current={resp.current.body.cashoutExternalVolume}
-              previous={resp.previous.body.cashoutExternalVolume}
+              current={resp.current.body.cashoutFiatVolume}
+              previous={resp.previous.body.cashoutFiatVolume}
             />
           </div>
         </Fragment>
@@ -151,8 +151,8 @@ function Metrics(): VNode {
           <i18n.Translate>Payout</i18n.Translate>
         </dt>
         <MetricValue
-          current={resp.current.body.talerPayoutInternalVolume}
-          previous={resp.previous.body.talerPayoutInternalVolume}
+          current={resp.current.body.talerOutVolume}
+          previous={resp.previous.body.talerOutVolume}
         />
       </div>
     </dl>
diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx 
b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
index 10be5ec11..525a170bc 100644
--- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx
+++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
@@ -16,19 +16,22 @@
 import {
   Amounts,
   TalerError,
-  TranslatedString
+  TranslatedString,
+  encodeCrock,
+  getRandomBytes
 } from "@gnu-taler/taler-util";
 import {
+  Attention,
+  ErrorLoading,
+  Loading,
+  LocalNotificationBanner,
+  ShowInputErrorLabel,
   useLocalNotification,
   useTranslationContext
 } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useEffect, useState } from "preact/hooks";
 import { mutate } from "swr";
-import { Attention } from "@gnu-taler/web-util/browser";
-import { ErrorLoading } from "@gnu-taler/web-util/browser";
-import { Loading } from "@gnu-taler/web-util/browser";
-import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser";
 import { useBankCoreApiContext } from "../../context/config.js";
 import { useAccountDetails } from "../../hooks/access.js";
 import { useBackendState } from "../../hooks/backend.js";
@@ -37,13 +40,11 @@ import {
 } from "../../hooks/circuit.js";
 import {
   TanChannel,
-  undefinedIfEmpty,
-  withRuntimeErrorHandling
+  undefinedIfEmpty
 } from "../../utils.js";
 import { LoginForm } from "../LoginForm.js";
 import { InputAmount } from "../PaytoWireTransferForm.js";
 import { assertUnreachable } from "../WithdrawalOperationPage.js";
-import { LocalNotificationBanner } from "@gnu-taler/web-util/browser";
 
 interface Props {
   account: string;
@@ -321,21 +322,6 @@ export function CreateCashout({
                 updateForm(structuredClone(form));
               }}
             />
-            <input
-              class={
-                "pure-button content " +
-                (form.channel === TanChannel.FILE
-                  ? "pure-button-primary"
-                  : "pure-button-secondary")
-              }
-              type="submit"
-              value={i18n.str`FILE`}
-              onClick={async (e) => {
-                e.preventDefault();
-                form.channel = TanChannel.FILE;
-                updateForm(structuredClone(form));
-              }}
-            />
           </div>
           <ShowInputErrorLabel
             message={errors?.channel}
@@ -363,7 +349,9 @@ export function CreateCashout({
 
               if (errors || !creds) return;
               await handleError(async () => {
+                const request_uid = encodeCrock(getRandomBytes(16))
                 const resp = await api.createCashout(creds, {
+                  request_uid,
                   amount_credit: Amounts.stringify(calc.credit),
                   amount_debit: Amounts.stringify(calc.debit),
                   subject: form.subject,
@@ -404,12 +392,18 @@ export function CreateCashout({
                       description: resp.detail.hint as TranslatedString,
                       debug: resp.detail,
                     });
-                    // case "": return notify({
-                    //   type: "error",
-                    //   title: i18n.str`This user is not allowed to make a 
cashout`,
-                    //   description: resp.detail.hint as TranslatedString,
-                    //   debug: resp.detail,
-                    // });
+                    case "request-already-used": return notify({
+                      type: "error",
+                      title: i18n.str`Duplicated request found, try again.`,
+                      description: resp.detail.hint as TranslatedString,
+                      debug: resp.detail,
+                    });
+                    case "tan-failed": return notify({
+                      type: "error",
+                      title: i18n.str`Server couldn't send the confirmation 
request.`,
+                      description: resp.detail.hint as TranslatedString,
+                      debug: resp.detail,
+                    });
                     default: assertUnreachable(resp)
                   }
                 }
diff --git a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx 
b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
index 4646e9220..ddfc18a0c 100644
--- a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
+++ b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
@@ -121,12 +121,12 @@ export function ShowCashoutDetails({
           </label>
           <input readOnly value={result.body.status} />
         </fieldset>
-        <fieldset>
+        {/* <fieldset>
           <label>
             <i18n.Translate>Destination</i18n.Translate>
           </label>
           <input readOnly value={result.body.credit_payto_uri} />
-        </fieldset>
+        </fieldset> */}
         {isPending ? (
           <fieldset>
             <label>
@@ -220,15 +220,33 @@ export function ShowCashoutDetails({
                         description: resp.detail.hint as TranslatedString,
                         debug: resp.detail,
                       })
-                      case "wrong-tan-or-credential": return notify({
+                      case "no-enough-balance": return notify({
+                        type: "error",
+                        title: i18n.str`The account does not have sufficient 
funds`,
+                        description: resp.detail.hint as TranslatedString,
+                        debug: resp.detail,
+                      });
+                      case "incorrect-exchange-rate": return notify({
+                        type: "error",
+                        title: i18n.str`The exchange rate was incorrectly 
applied`,
+                        description: resp.detail.hint as TranslatedString,
+                        debug: resp.detail,
+                      });
+                      case "already-aborted": return notify({
+                        type: "error",
+                        title: i18n.str`The cashout operation is already 
aborted.`,
+                        description: resp.detail.hint as TranslatedString,
+                        debug: resp.detail,
+                      });
+                      case "no-cashout-payto": return notify({
                         type: "error",
-                        title: i18n.str`Invalid code or credentials.`,
+                        title: i18n.str`Missing destination account.`,
                         description: resp.detail.hint as TranslatedString,
                         debug: resp.detail,
                       })
-                      case "cashout-address-changed": return notify({
+                      case "too-many-attempts": return notify({
                         type: "error",
-                        title: i18n.str`The cash-out address between the 
creation and the confirmation changed.`,
+                        title: i18n.str`Too many failed attempts.`,
                         description: resp.detail.hint as TranslatedString,
                         debug: resp.detail,
                       })
diff --git a/packages/demobank-ui/src/utils.ts 
b/packages/demobank-ui/src/utils.ts
index 437618150..18abf28a9 100644
--- a/packages/demobank-ui/src/utils.ts
+++ b/packages/demobank-ui/src/utils.ts
@@ -78,7 +78,6 @@ export type RecursivePartial<T> = {
 export enum TanChannel {
   SMS = "sms",
   EMAIL = "email",
-  FILE = "file",
 }
 export enum CashoutStatus {
   // The payment was initiated after a valid
diff --git a/packages/taler-harness/src/http-client/bank-core.ts 
b/packages/taler-harness/src/http-client/bank-core.ts
index 9919fc0a7..22a10580d 100644
--- a/packages/taler-harness/src/http-client/bank-core.ts
+++ b/packages/taler-harness/src/http-client/bank-core.ts
@@ -16,13 +16,18 @@ export function createTestForBankCore(api: 
TalerCoreBankHttpClient, adminToken:
       "no-contact-info": undefined,
       "no-enough-balance": undefined,
       "cashout-not-supported": undefined,
+      "request-already-used": undefined,
+      "tan-failed": undefined,
       success: undefined,
     },
     test_confirmCashoutById: {
-      "cashout-address-changed": undefined,
+      "already-aborted": undefined,
+      "incorrect-exchange-rate": undefined,
+      "no-cashout-payto": undefined,
+      "no-enough-balance": undefined,
+      "too-many-attempts": undefined,
       "cashout-not-supported": undefined,
       "not-found": undefined,
-      "wrong-tan-or-credential": undefined,
       success: undefined,
     },
     test_getAccountCashouts: {
@@ -37,8 +42,18 @@ export function createTestForBankCore(api: 
TalerCoreBankHttpClient, adminToken:
     },
     test_getCashoutRate: {
       "cashout-not-supported": undefined,
-      "not-supported": undefined,
       "wrong-calculation": undefined,
+      "amount-too-small": undefined,
+      "missing-params": undefined,
+      "wrong-currency": undefined,
+      success: undefined,
+    },
+    test_getCashinRate: {
+      "cashout-not-supported": undefined,
+      "wrong-calculation": undefined,
+      "amount-too-small": undefined,
+      "missing-params": undefined,
+      "wrong-currency": undefined,
       success: undefined,
     },
     test_getGlobalCashouts: {
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index 1107a3c93..0b99943a3 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -31,7 +31,7 @@ import { TalerAuthenticationHttpClient } from 
"./authentication.js";
 import { TalerBankIntegrationHttpClient } from "./bank-integration.js";
 import { TalerRevenueHttpClient } from "./bank-revenue.js";
 import { TalerWireGatewayHttpClient } from "./bank-wire.js";
-import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, 
codecForAccountData, codecForBankAccountCreateWithdrawalResponse, 
codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, 
codecForBankAccountTransactionsResponse, codecForCashoutConversionResponse, 
codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, 
codecForCoreBankConfig, codecForGlobalCashouts, 
codecForListBankAccountsResponse, codecForMonitorResponse, codecForPublicAccoun 
[...]
+import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, 
codecForAccountData, codecForBankAccountCreateWithdrawalResponse, 
codecForBankAccountGetWithdrawalResponse, codecForBankAccountTransactionInfo, 
codecForBankAccountTransactionsResponse, codecForCashinConversionResponse, 
codecForCashoutConversionResponse, codecForCashoutPending, 
codecForCashoutStatusResponse, codecForCashouts, codecForCoreBankConfig, 
codecForGlobalCashouts, codecForListBankAccountsResponse, codecForMon [...]
 import { addPaginationParams, makeBearerTokenAuthHeader } from "./utils.js";
 
 
@@ -181,6 +181,9 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      //FIXME: add code to split cases
+      // * An admin account tried to make its account an exchange
+      // * A non-admin user tried to change properties reserved for the admin
       case HttpStatusCode.Forbidden: return 
opKnownFailure("old-password-invalid-or-not-allowed", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -444,13 +447,15 @@ export class TalerCoreBankHttpClient {
         const body = await resp.json()
         const details = codecForTalerErrorDetail().decode(body)
         switch (details.code) {
+          case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED: return 
opKnownFailure("request-already-used", resp);
           case TalerErrorCode.BANK_BAD_CONVERSION: return 
opKnownFailure("incorrect-exchange-rate", resp);
           case TalerErrorCode.BANK_MISSING_TAN_INFO: return 
opKnownFailure("no-contact-info", resp);
           case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("no-enough-balance", resp);
           default: return opUnknownFailure(resp, body)
         }
       }
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.BadGateway: return opKnownFailure("tan-failed", 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -472,7 +477,7 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
       case HttpStatusCode.Conflict: return opKnownFailure("already-confirmed", 
resp);
       //FIXME: should be 404 ?
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -492,11 +497,22 @@ export class TalerCoreBankHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.Forbidden: return 
opKnownFailure("wrong-tan-or-credential", resp);
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      case HttpStatusCode.Conflict: return 
opKnownFailure("cashout-address-changed", resp);
-      //FIXME: should be 404 ?
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      // case HttpStatusCode.Forbidden: return 
opKnownFailure("wrong-tan-or-credential", resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return 
opKnownFailure("already-aborted", resp);
+          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return 
opKnownFailure("no-cashout-payto", resp);
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownFailure("no-enough-balance", resp);
+          case TalerErrorCode.BANK_BAD_CONVERSION: return 
opKnownFailure("incorrect-exchange-rate", resp);
+          // case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED: return 
opKnownFailure("no-enough-balance", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
+      case HttpStatusCode.TooManyRequests: return 
opKnownFailure("too-many-attempts", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -518,7 +534,7 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
       case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
       case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", 
resp);;
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -538,7 +554,7 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutStatusResponse())
       case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -559,7 +575,7 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForGlobalCashouts())
       case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -574,24 +590,61 @@ export class TalerCoreBankHttpClient {
       url.searchParams.set("amount_debit", Amounts.stringify(conversion.debit))
     }
     if (conversion.credit) {
-      url.searchParams.set("amount_debit", 
Amounts.stringify(conversion.credit))
+      url.searchParams.set("amount_credit", 
Amounts.stringify(conversion.credit))
     }
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashoutConversionResponse())
-      // FIXME: error code for
-      // * the requested currency was not supported
-      // * the calculation is not correct
-      case HttpStatusCode.BadRequest: return 
opKnownFailure("wrong-calculation", resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-supported", 
resp);
-      //FIXME: should be 404 ?
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownFailure("cashout-not-supported", resp);
+      case HttpStatusCode.BadRequest: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.GENERIC_PARAMETER_MISSING: return 
opKnownFailure("missing-params", resp);
+          case TalerErrorCode.GENERIC_PARAMETER_MALFORMED : return 
opKnownFailure("wrong-calculation", resp);
+          case TalerErrorCode.GENERIC_CURRENCY_MISMATCH: return 
opKnownFailure("wrong-currency", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
+      case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", 
resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
+  /**
+   * https://docs.taler.net/core/api-corebank.html#get--cashin-rate
+   * 
+   */
+  async getCashinRate(conversion: { debit?: AmountJson, credit?: AmountJson }) 
{
+    const url = new URL(`cashin-rate`, this.baseUrl);
+    if (conversion.debit) {
+      url.searchParams.set("amount_debit", Amounts.stringify(conversion.debit))
+    }
+    if (conversion.credit) {
+      url.searchParams.set("amount_credit", 
Amounts.stringify(conversion.credit))
+    }
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "GET",
+    });
+    switch (resp.status) {
+      case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCashinConversionResponse())
+      case HttpStatusCode.BadRequest: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.GENERIC_PARAMETER_MISSING: return 
opKnownFailure("missing-params", resp);
+          case TalerErrorCode.GENERIC_PARAMETER_MALFORMED : return 
opKnownFailure("wrong-calculation", resp);
+          case TalerErrorCode.GENERIC_CURRENCY_MISMATCH: return 
opKnownFailure("wrong-currency", resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
+      case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", 
resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownFailure("cashout-not-supported", resp);
+      default: return opUnknownFailure(resp, await resp.text())
+    }
+  }
   //
   // MONITOR
   //
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 77004cf5b..f6542abcd 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -357,13 +357,13 @@ export const codecForBankAccountTransactionsResponse =
 export const codecForBankAccountTransactionInfo =
   (): Codec<TalerCorebankApi.BankAccountTransactionInfo> =>
     buildCodecForObject<TalerCorebankApi.BankAccountTransactionInfo>()
-      .property("amount", codecForAmountString())
       .property("creditor_payto_uri", codecForPaytoString())
-      .property("date", codecForTimestamp)
       .property("debtor_payto_uri", codecForPaytoString())
+      .property("amount", codecForAmountString())
       .property("direction", codecForEither(codecForConstString("debit"), 
codecForConstString("credit")))
-      .property("row_id", codecForNumber())
       .property("subject", codecForString())
+      .property("row_id", codecForNumber())
+      .property("date", codecForTimestamp)
       .build("TalerCorebankApi.BankAccountTransactionInfo");
 
 export const codecForBankAccountCreateWithdrawalResponse =
@@ -376,8 +376,8 @@ export const codecForBankAccountCreateWithdrawalResponse =
 export const codecForBankAccountGetWithdrawalResponse =
   (): Codec<TalerCorebankApi.BankAccountGetWithdrawalResponse> =>
     buildCodecForObject<TalerCorebankApi.BankAccountGetWithdrawalResponse>()
-      .property("aborted", codecForBoolean())
       .property("amount", codecForAmountString())
+      .property("aborted", codecForBoolean())
       .property("confirmation_done", codecForBoolean())
       .property("selected_exchange_account", 
codecOptional(codecForPaytoString()))
       .property("selected_reserve_pub", codecOptional(codecForString()))
@@ -397,6 +397,13 @@ export const codecForCashoutConversionResponse =
       .property("amount_debit", codecForAmountString())
       .build("TalerCorebankApi.CashoutConversionResponse");
 
+export const codecForCashinConversionResponse =
+  (): Codec<TalerCorebankApi.CashinConversionResponse> =>
+    buildCodecForObject<TalerCorebankApi.CashinConversionResponse>()
+      .property("amount_credit", codecForAmountString())
+      .property("amount_debit", codecForAmountString())
+      .build("TalerCorebankApi.CashinConversionResponse");
+
 export const codecForCashouts =
   (): Codec<TalerCorebankApi.Cashouts> =>
     buildCodecForObject<TalerCorebankApi.Cashouts>()
@@ -407,7 +414,7 @@ export const codecForCashoutInfo =
   (): Codec<TalerCorebankApi.CashoutInfo> =>
     buildCodecForObject<TalerCorebankApi.CashoutInfo>()
       .property("cashout_id", codecForString())
-      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("confirmed"),))
+      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("aborted"), codecForConstString("confirmed"),))
       .build("TalerCorebankApi.CashoutInfo");
 
 export const codecForGlobalCashouts =
@@ -421,7 +428,7 @@ export const codecForGlobalCashoutInfo =
     buildCodecForObject<TalerCorebankApi.GlobalCashoutInfo>()
       .property("cashout_id", codecForString())
       .property("username", codecForString())
-      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("confirmed"),))
+      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("aborted"), codecForConstString("confirmed"),))
       .build("TalerCorebankApi.GlobalCashoutInfo");
 
 export const codecForCashoutStatusResponse =
@@ -431,8 +438,8 @@ export const codecForCashoutStatusResponse =
       .property("amount_debit", codecForAmountString())
       .property("confirmation_time", codecForTimestamp)
       .property("creation_time", codecForTimestamp)
-      .property("credit_payto_uri", codecForPaytoString())
-      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("confirmed")))
+      // .property("credit_payto_uri", codecForPaytoString())
+      .property("status", codecForEither(codecForConstString("pending"), 
codecForConstString("aborted"), codecForConstString("confirmed")))
       .property("subject", codecForString())
       .build("TalerCorebankApi.CashoutStatusResponse");
 
@@ -448,28 +455,34 @@ export const codecForConversionRatesResponse =
 
 export const codecForMonitorResponse = (): 
Codec<TalerCorebankApi.MonitorResponse> => 
buildCodecForUnion<TalerCorebankApi.MonitorResponse>()
   .discriminateOn("type")
-  .alternative("just-payouts", codecForMonitorResponseJustPayout())
-  .alternative("with-cashout", codecForMonitorResponseWithCashout())
+  .alternative("no-conversions", codecForMonitorNoConversion())
+  .alternative("with-conversions", codecForMonitorWithCashout())
   .build("TalerWireGatewayApi.IncomingBankTransaction");
 
-export const codecForMonitorResponseJustPayout =
-  (): Codec<TalerCorebankApi.MonitorJustPayouts> =>
-    buildCodecForObject<TalerCorebankApi.MonitorJustPayouts>()
-      .property("type", codecForConstString("just-payouts"))
-      .property("talerPayoutCount", codecForNumber())
-      .property("talerPayoutInternalVolume", codecForAmountString())
+export const codecForMonitorNoConversion =
+  (): Codec<TalerCorebankApi.MonitorNoConversion> =>
+    buildCodecForObject<TalerCorebankApi.MonitorNoConversion>()
+      .property("type", codecForConstString("no-conversions"))
+      .property("talerInCount", codecForNumber())
+      .property("talerInVolume", codecForAmountString())
+      .property("talerOutCount", codecForNumber())
+      .property("talerOutVolume", codecForAmountString())
       .build("TalerCorebankApi.MonitorJustPayouts");
 
-export const codecForMonitorResponseWithCashout =
-  (): Codec<TalerCorebankApi.MonitorWithCashout> =>
-    buildCodecForObject<TalerCorebankApi.MonitorWithCashout>()
-      .property("type", codecForConstString("with-cashout"))
-      .property("cashinCount", (codecForNumber()))
-      .property("cashinExternalVolume", (codecForAmountString()))
-      .property("cashoutCount", (codecForNumber()))
-      .property("cashoutExternalVolume", (codecForAmountString()))
-      .property("talerPayoutCount", codecForNumber())
-      .property("talerPayoutInternalVolume", codecForAmountString())
+export const codecForMonitorWithCashout =
+  (): Codec<TalerCorebankApi.MonitorWithConversion> =>
+    buildCodecForObject<TalerCorebankApi.MonitorWithConversion>()
+      .property("type", codecForConstString("with-conversions"))
+      .property("cashinCount", codecForNumber())
+      .property("cashinFiatVolume", codecForAmountString())
+      .property("cashinRegionalVolume", codecForAmountString())
+      .property("cashoutCount", codecForNumber())
+      .property("cashoutFiatVolume", codecForAmountString())
+      .property("cashoutRegionalVolume", codecForAmountString())
+      .property("talerInCount", codecForNumber())
+      .property("talerInVolume", codecForAmountString())
+      .property("talerOutCount", codecForNumber())
+      .property("talerOutVolume", codecForAmountString())
       .build("TalerCorebankApi.MonitorWithCashout");
 
 export const codecForBankVersion =
@@ -697,7 +710,6 @@ const codecForDecimalNumber = codecForNumber
 enum TanChannel {
   SMS = "sms",
   EMAIL = "email",
-  FILE = "file"
 }
 
 export namespace TalerWireGatewayApi {
@@ -1174,7 +1186,7 @@ export namespace TalerCorebankApi {
 
     // If present, change the is_exchange configuration.
     // See RegisterAccountRequest
-    is_exchange?: boolean;
+    is_taler_exchange?: boolean;
 
     // If present, change the max debit allowed for this user
     // Only admin can change this property.
@@ -1252,10 +1264,15 @@ export namespace TalerCorebankApi {
 
   export interface CashoutRequest {
 
+    // Nonce to make the request idempotent.  Requests with the same
+    // request_uid that differ in any of the other fields
+    // are rejected.
+    request_uid: ShortHashCode;
+
     // Optional subject to associate to the
     // cashout operation.  This data will appear
     // as the incoming wire transfer subject in
-    // the user's external bank account.
+    // the user's fiat bank account.
     subject?: string;
 
     // That is the plain amount that the user specified
@@ -1301,6 +1318,15 @@ export namespace TalerCorebankApi {
     amount_credit: AmountString;
   }
 
+  export interface CashinConversionResponse {
+    // Amount that the user will get deducted from their fiat
+    // bank account, according to the 'amount_credit' value.
+    amount_debit: AmountString;
+    // Amount that the user will receive in their regional
+    // bank account, according to 'amount_debit'.
+    amount_credit: AmountString;
+  }
+
   export interface Cashouts {
     // Every string represents a cash-out operation ID.
     cashouts: CashoutInfo[];
@@ -1308,7 +1334,7 @@ export namespace TalerCorebankApi {
 
   export interface CashoutInfo {
     cashout_id: string;
-    status: "pending" | "confirmed";
+    status: "pending" | "aborted" | "confirmed";
   }
   export interface GlobalCashouts {
     // Every string represents a cash-out operation ID.
@@ -1317,11 +1343,11 @@ export namespace TalerCorebankApi {
   export interface GlobalCashoutInfo {
     cashout_id: string;
     username: string;
-    status: "pending" | "confirmed";
+    status: "pending" | "aborted" | "confirmed";
   }
 
   export interface CashoutStatusResponse {
-    status: "pending" | "confirmed";
+    status: "pending" | "aborted" | "confirmed";
 
     // Amount debited to the internal
     // regional currency bank account.
@@ -1335,7 +1361,7 @@ export namespace TalerCorebankApi {
 
     // Fiat bank account that will receive the cashed out amount.
     // Specified as a payto URI.
-    credit_payto_uri: PaytoString;
+    // credit_payto_uri: PaytoString;
 
     // Time when the cashout was created.
     creation_time: Timestamp;
@@ -1365,59 +1391,72 @@ export namespace TalerCorebankApi {
   }
 
   export type MonitorResponse =
-    | MonitorJustPayouts
-    | MonitorWithCashout;
+    | MonitorNoConversion
+    | MonitorWithConversion;
 
   // Monitoring stats when conversion is not supported
-  export interface MonitorJustPayouts {
-    type: "just-payouts";
+  export interface MonitorNoConversion {
+    type: "no-conversions";
+
+    // How many payments were made to a Taler exchange by another
+    // bank account.
+    talerInCount: number;
 
-    // This number identifies how many payments were made by a
-    // Taler exchange to a merchant bank account in the internal
-    // currency, in the timeframe specified in the request.
-    talerPayoutCount: number;
+    // Overall volume that has been paid to a Taler
+    // exchange by another bank account.
+    talerInVolume: AmountString;
 
-    // This amount accounts the overall *internal* currency that
-    // has been paid by a Taler exchange to a merchant internal
-    // bank account, in the timeframe specified in the request.
-    talerPayoutInternalVolume: AmountString;
+    // How many payments were made by a Taler exchange to another
+    // bank account.
+    talerOutCount: number;
+
+    // Overall volume that has been paid by a Taler
+    // exchange to another bank account.
+    talerOutVolume: AmountString;
   }
   // Monitoring stats when conversion is supported
-  export interface MonitorWithCashout {
-    type: "with-cashout";
+  export interface MonitorWithConversion {
+    type: "with-conversions";
 
-    // This number identifies how many cashin operations
-    // took place in the timeframe specified in the request.
-    // This number corresponds to how many withdrawals have
-    // been initiated by a wallet owner.  Note: wallet owners
+    // How many cashin operations were confirmed by a
+    // wallet owner. Note: wallet owners
     // are NOT required to be customers of the libeufin-bank.
     cashinCount: number;
 
-    // This amount accounts how much external currency has been
-    // spent to withdraw Taler coins in the internal currency.
-    // The exact amount of internal currency being created can be
-    // calculated using the advertised conversion rates.
-    cashinExternalVolume: AmountString;
+    // Overall regional currency that has been paid by the regional admin 
account
+    // to regional bank accounts to fulfill all the confirmed cashin 
operations.
+    cashinRegionalVolume: AmountString;
+
+    // Overall fiat currency that has been paid to the fiat admin account
+    // by fiat bank accounts to fulfill all the confirmed cashin operations.
+    cashinFiatVolume: AmountString;
 
-    // This number identifies how many cashout operations were
-    // confirmed in the timeframe speficied in the request.
+    // How many cashout operations were confirmed.
     cashoutCount: number;
 
-    // This amount corresponds to how much *external* currency was
-    // paid by the libeufin-bank administrator to fulfill all the
-    // confirmed cashouts related to the timeframe specified in the
-    // request.
-    cashoutExternalVolume: AmountString;
-
-    // This number identifies how many payments were made by a
-    // Taler exchange to a merchant bank account in the internal
-    // currency, in the timeframe specified in the request.
-    talerPayoutCount: number;
-
-    // This amount accounts the overall *internal* currency that
-    // has been paid by a Taler exchange to a merchant internal
-    // bank account, in the timeframe specified in the request.
-    talerPayoutInternalVolume: AmountString;
+    // Overall regional currency that has been paid to the regional admin 
account
+    // by fiat bank accounts to fulfill all the confirmed cashout operations.
+    cashoutRegionalVolume: AmountString;
+
+    // Overall fiat currency that has been paid by the fiat admin account
+    // to fiat bank accounts to fulfill all the confirmed cashout operations.
+    cashoutFiatVolume: AmountString;
+
+    // How many payments were made to a Taler exchange by another
+    // bank account.
+    talerInCount: number;
+
+    // Overall volume that has been paid to a Taler
+    // exchange by another bank account.
+    talerInVolume: AmountString;
+
+    // How many payments were made by a Taler exchange to another
+    // bank account.
+    talerOutCount: number;
+
+    // Overall volume that has been paid by a Taler
+    // exchange to another bank account.
+    talerOutVolume: AmountString;
   }
 
 
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index 05f979a37..7c0f1938d 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -88,7 +88,7 @@ export function DeveloperPage(): VNode {
 
 type CoinsInfo = CoinDumpJson["coins"];
 type CalculatedCoinfInfo = {
-  ageKeysCount: number | undefined;
+  // ageKeysCount: number | undefined;
   denom_value: number;
   denom_fraction: number;
   //remain_value: number;
@@ -152,7 +152,7 @@ export function View({
         currencies[cur.exchange_base_url] = denom.currency;
       }
       prev[cur.exchange_base_url].push({
-        ageKeysCount: cur.ageCommitmentProof?.proof.privateKeys.length,
+        // ageKeysCount: cur.ageCommitmentProof?.proof.privateKeys.length,
         denom_value: denom.value,
         denom_fraction: denom.fraction,
         // remain_value: parseFloat(
@@ -544,7 +544,7 @@ function ShowAllCoins({
                 </td>
                 <td>{c.status}</td>
                 <td>{c.from_refresh ? "true" : "false"}</td>
-                <td>{String(c.ageKeysCount)}</td>
+                {/* <td>{String(c.ageKeysCount)}</td> */}
               </tr>
             );
           })}
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 56d0ef7bd..dcc3c43e3 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -42,6 +42,7 @@ import { Button } from "../mui/Button.js";
 import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
 import DownloadIcon from "../svg/download_24px.inline.svg";
 import UploadIcon from "../svg/upload_24px.inline.svg";
+import { getDate, startOfDay } from "date-fns";
 
 interface Props {
   currency?: string;
@@ -154,14 +155,14 @@ export function HistoryView({
 
   const datesWithTransaction: string[] = [];
   const byDate = ts.reduce((rv, x) => {
-    const theDate =
-      x.timestamp.t_s === "never" ? 0 : normalizeToDay(x.timestamp.t_s * 1000);
-    if (theDate) {
-      if (!rv[theDate]) {
-        rv[theDate] = [];
-        datesWithTransaction.push(String(theDate));
+    const startDay =
+      x.timestamp.t_s === "never" ? 0 : startOfDay(x.timestamp.t_s * 
1000).getTime();
+    if (startDay) {
+      if (!rv[startDay]) {
+        rv[startDay] = [];
+        datesWithTransaction.push(String(startDay));
       }
-      rv[theDate].push(x);
+      rv[startDay].push(x);
     }
 
     return rv;
diff --git a/packages/taler-wallet-webextension/static/img/icon.png 
b/packages/taler-wallet-webextension/static/img/icon.png
deleted file mode 100644
index b4733bebc..000000000
Binary files a/packages/taler-wallet-webextension/static/img/icon.png and 
/dev/null differ
diff --git a/packages/taler-wallet-webextension/static/wallet.html 
b/packages/taler-wallet-webextension/static/wallet.html
index 32a98130b..c8baa7e4d 100644
--- a/packages/taler-wallet-webextension/static/wallet.html
+++ b/packages/taler-wallet-webextension/static/wallet.html
@@ -1,33 +1,40 @@
 <!DOCTYPE html>
 <html>
-  <head>
-    <title>GNU Taler Wallet - WebExtension</title>
-    <meta charset="utf-8" />
-    <link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
-    <link rel="stylesheet" type="text/css" href="/static/font/import.css" />
-    <link rel="icon" href="/static/img/icon.png" />
-    <script src="/dist/walletEntryPoint.js"></script>
-    <style>
-      html {
-        font-family: sans-serif; /* 1 */
-      }
-      h1 {
-        font-size: 2em;
-      }
-      input {
-        font: inherit;
-      }
-      body {
-        margin: 0;
-        font-size: 100%;
-        padding: 0;
-        background-color: #f8faf7;
-        font-family: Arial, Helvetica, sans-serif;
-      }
-    </style>
-  </head>
 
-  <body>
-    <div id="container" class="wallet-container"></div>
-  </body>
-</html>
+<head>
+  <title>GNU Taler Wallet - WebExtension</title>
+  <meta charset="utf-8" />
+  <link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
+  <link rel="stylesheet" type="text/css" href="/static/font/import.css" />
+  <link rel="icon"
+    
href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn
 [...]
+  <script src="/dist/walletEntryPoint.js"></script>
+  <style>
+    html {
+      font-family: sans-serif;
+      /* 1 */
+    }
+
+    h1 {
+      font-size: 2em;
+    }
+
+    input {
+      font: inherit;
+    }
+
+    body {
+      margin: 0;
+      font-size: 100%;
+      padding: 0;
+      background-color: #f8faf7;
+      font-family: Arial, Helvetica, sans-serif;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="container" class="wallet-container"></div>
+</body>
+
+</html>
\ No newline at end of file

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