gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (ef4cc1a1c -> d845c0cf2)


From: gnunet
Subject: [taler-wallet-core] branch master updated (ef4cc1a1c -> d845c0cf2)
Date: Fri, 19 Jan 2024 21:11:10 +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 ef4cc1a1c wallet-core: fix bugs.taler.net/n/7836
     new a04e822af fixes #8146
     new d845c0cf2 fixes #8147

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:
 .../demobank-ui/src/components/Cashouts/views.tsx  |  37 ++--
 packages/demobank-ui/src/pages/LoginForm.tsx       |   6 +-
 .../demobank-ui/src/pages/RegistrationPage.tsx     |   4 +-
 .../demobank-ui/src/pages/SolveChallengePage.tsx   |  12 ++
 .../src/pages/account/ShowAccountDetails.tsx       |   4 +-
 packages/demobank-ui/src/pages/admin/AdminHome.tsx |  25 ++-
 .../src/pages/business/CreateCashout.tsx           |  10 +
 .../src/pages/business/ShowCashoutDetails.tsx      | 193 +------------------
 .../taler-util/src/http-client/authentication.ts   |   8 +-
 .../taler-util/src/http-client/bank-conversion.ts  |  36 ++--
 packages/taler-util/src/http-client/bank-core.ts   | 204 ++++++++-------------
 .../taler-util/src/http-client/bank-integration.ts |  47 +++--
 .../taler-util/src/http-client/bank-revenue.ts     |  38 +++-
 packages/taler-util/src/http-client/bank-wire.ts   |  80 +++++---
 packages/taler-util/src/http-client/exchange.ts    |  31 ++--
 packages/taler-util/src/http-client/merchant.ts    |   2 +-
 packages/taler-util/src/http-client/types.ts       | 124 +++----------
 packages/taler-util/src/http-client/utils.ts       |  12 +-
 packages/taler-util/src/operation.ts               |   4 -
 packages/web-util/src/context/api.ts               |   2 +-
 20 files changed, 351 insertions(+), 528 deletions(-)

diff --git a/packages/demobank-ui/src/components/Cashouts/views.tsx 
b/packages/demobank-ui/src/components/Cashouts/views.tsx
index c3fdec796..cb1c24aa7 100644
--- a/packages/demobank-ui/src/components/Cashouts/views.tsx
+++ b/packages/demobank-ui/src/components/Cashouts/views.tsx
@@ -32,13 +32,11 @@ export function FailedView({ error }: State.Failed) {
         {error.detail.hint}
       </div>
     </Attention>
-    case HttpStatusCode.NotFound: return <Attention type="danger"
-      title={i18n.str`Account not found.`}>
-      <div class="mt-2 text-sm text-red-700">
-        {error.detail.hint}
-      </div>
-    </Attention>
-    default: assertUnreachable(error)
+    case HttpStatusCode.NotImplemented: {
+      return <Attention type="danger" title={i18n.str`Cashout not 
implemented`}>
+      </Attention>;
+    }
+    default: assertUnreachable(error.case)
   }
 }
 
@@ -51,6 +49,16 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
   if (resp instanceof TalerError) {
     return <ErrorLoadingWithDebug error={resp} />
   }
+  if (resp.type === "fail") {
+    switch (resp.case) {
+      case HttpStatusCode.NotImplemented: {
+        return <Attention type="danger" title={i18n.str`Cashout not 
implemented`}>
+        </Attention>;
+      }
+      default: assertUnreachable(resp.case)
+    }
+  }
+
   if (!cashouts.length) return <div />
   const txByDate = cashouts.reduce((prev, cur) => {
     const d = cur.creation_time.t_s === "never"
@@ -74,10 +82,8 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
           <thead>
             <tr>
               <th scope="col" class="                     pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Created`}</th>
-              <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Confirmed`}</th>
               <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Total debit`}</th>
               <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Total credit`}</th>
-              <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Status`}</th>
               <th scope="col" class="hidden sm:table-cell pl-2 py-3.5 
text-left text-sm font-semibold text-gray-900">{i18n.str`Subject`}</th>
             </tr>
           </thead>
@@ -91,9 +97,6 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
                 </tr>
                 {txs.map(item => {
                   const creationTime = item.creation_time.t_s === "never" ? "" 
: format(item.creation_time.t_s * 1000, "HH:mm:ss", { locale: dateLocale })
-                  const confirmationTime = item.confirmation_time
-                    ? item.confirmation_time.t_s === "never" ? i18n.str`never` 
: format(item.confirmation_time.t_s, "dd/MM/yyyy HH:mm:ss", { locale: 
dateLocale })
-                    : "-"
                   return (<tr key={idx} class="border-b border-gray-200 
hover:bg-gray-200 last:border-none">
 
                     <td onClick={(e) => {
@@ -101,6 +104,8 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
                       onSelected(item.id);
                     }} class="relative py-2 pl-2 pr-2 text-sm ">
                       <div class="font-medium 
text-gray-900">{creationTime}</div>
+                      {//FIXME: implement responsive view
+                      }
                       {/* <dl class="font-normal sm:hidden">
                         <dt class="sr-only 
sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt>
                         <dd class="mt-1 truncate text-gray-700">
@@ -123,10 +128,6 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
                         </dd>
                       </dl> */}
                     </td>
-                    <td onClick={(e) => {
-                      e.preventDefault();
-                      onSelected(item.id);
-                    }} class="hidden sm:table-cell px-3 py-3.5 text-sm 
text-gray-500 cursor-pointer">{confirmationTime}</td>
                     <td onClick={(e) => {
                       e.preventDefault();
                       onSelected(item.id);
@@ -136,10 +137,6 @@ export function ReadyView({ cashouts, onSelected }: 
State.Ready): VNode {
                       onSelected(item.id);
                     }} class="hidden sm:table-cell px-3 py-3.5 text-sm 
text-green-600 cursor-pointer"><RenderAmount 
value={Amounts.parseOrThrow(item.amount_credit)} 
spec={resp.body.fiat_currency_specification} /></td>
 
-                    <td onClick={(e) => {
-                      e.preventDefault();
-                      onSelected(item.id);
-                    }} class="hidden sm:table-cell px-3 py-3.5 text-sm 
text-gray-500 cursor-pointer">{item.status}</td>
                     <td onClick={(e) => {
                       e.preventDefault();
                       onSelected(item.id);
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx 
b/packages/demobank-ui/src/pages/LoginForm.tsx
index 627252682..7ec490c19 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { TranslatedString } from "@gnu-taler/taler-util";
+import { HttpStatusCode, TranslatedString } from "@gnu-taler/taler-util";
 import { LocalNotificationBanner, ShowInputErrorLabel, useLocalNotification, 
useTranslationContext } from "@gnu-taler/web-util/browser";
 import { Fragment, VNode, h } from "preact";
 import { useEffect, useRef, useState } from "preact/hooks";
@@ -76,13 +76,13 @@ export function LoginForm({ currentUser, fixedUser, 
onRegister }: { fixedUser?:
         backend.logIn({ username, token: resp.body.access_token });
       } else {
         switch (resp.case) {
-          case "wrong-credentials": return notify({
+          case HttpStatusCode.Unauthorized: return notify({
             type: "error",
             title: i18n.str`Wrong credentials for "${username}"`,
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
-          case "not-found": return notify({
+          case HttpStatusCode.NotFound: return notify({
             type: "error",
             title: i18n.str`Account not found`,
             description: resp.detail.hint as TranslatedString,
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx 
b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index 005a0bc2c..e948a5dad 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -177,13 +177,13 @@ function RegistrationForm({ onComplete, onCancel }: { 
onComplete: () => void, on
           backend.logIn({ username, token: resp.body.access_token });
         } else {
           switch (resp.case) {
-            case "wrong-credentials": return notify({
+            case HttpStatusCode.Unauthorized: return notify({
               type: "error",
               title: i18n.str`Wrong credentials for "${username}"`,
               description: resp.detail.hint as TranslatedString,
               debug: resp.detail,
             })
-            case "not-found": return notify({
+            case HttpStatusCode.NotFound: return notify({
               type: "error",
               title: i18n.str`Account not found`,
               description: resp.detail.hint as TranslatedString,
diff --git a/packages/demobank-ui/src/pages/SolveChallengePage.tsx 
b/packages/demobank-ui/src/pages/SolveChallengePage.tsx
index 3647f2b65..d0ac5ab75 100644
--- a/packages/demobank-ui/src/pages/SolveChallengePage.tsx
+++ b/packages/demobank-ui/src/pages/SolveChallengePage.tsx
@@ -27,6 +27,7 @@ import {
   parsePaytoUri
 } from "@gnu-taler/taler-util";
 import {
+  Attention,
   Loading,
   LocalNotificationBanner,
   ShowInputErrorLabel,
@@ -528,6 +529,17 @@ function ShowCashoutDetails({ request }: { request: 
TalerCorebankApi.CashoutRequ
   if (info instanceof TalerError) {
     return <ErrorLoadingWithDebug error={info} />
   }
+  if (info.type === "fail") {
+    switch (info.case) {
+      case HttpStatusCode.NotImplemented: {
+        return <Attention type="danger" title={i18n.str`Cashout not 
implemented`}>
+        </Attention>;
+      }
+      default: assertUnreachable(info.case)
+    }
+  }
+
+
   return <Fragment>
     {request.subject !== undefined &&
       <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx 
b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
index ca3e2fbdf..0dfdb39f3 100644
--- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
+++ b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
@@ -93,9 +93,9 @@ export function ShowAccountDetails({
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
-          case TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT: return notify({
+          case TalerErrorCode.BANK_MISSING_TAN_INFO: return notify({
             type: "error",
-            title: i18n.str`You can't change the contact data, please contact 
the your account administrator.`,
+            title: i18n.str`No information for the selected authentication 
channel.`,
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
diff --git a/packages/demobank-ui/src/pages/admin/AdminHome.tsx 
b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
index c03f228cd..b7ef3aa00 100644
--- a/packages/demobank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
@@ -1,5 +1,5 @@
-import { AmountString, Amounts, CurrencySpecification, TalerCorebankApi, 
TalerError, assertUnreachable } from "@gnu-taler/taler-util";
-import { useLang, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { AmountString, Amounts, CurrencySpecification, HttpStatusCode, 
TalerCorebankApi, TalerError, assertUnreachable } from "@gnu-taler/taler-util";
+import { Attention, useLang, useTranslationContext } from 
"@gnu-taler/web-util/browser";
 import { format, getDate, getHours, getMonth, getYear, setDate, setHours, 
setMonth, setYear, sub } from "date-fns";
 import { Fragment, VNode, h } from "preact";
 import { useState } from "preact/hooks";
@@ -90,10 +90,23 @@ function Metrics(): VNode {
   if (resp instanceof TalerError) {
     return <ErrorLoadingWithDebug error={resp} />
   }
+  if (!respInfo) return <Fragment />;
+  if (respInfo instanceof TalerError) {
+    return <ErrorLoadingWithDebug error={respInfo} />
+  }
+  if (respInfo.type === "fail") {
+    switch (respInfo.case) {
+      case HttpStatusCode.NotImplemented: {
+        return <Attention type="danger" title={i18n.str`Cashout not 
implemented`}>
+        </Attention>;
+      }
+      default: assertUnreachable(respInfo.case)
+    }
+  }
+
   if (resp.current.type !== "ok" || resp.previous.type !== "ok") {
     return <Fragment />
   }
-  const fiatSpec = respInfo && (!(respInfo instanceof TalerError)) ? 
respInfo.body.fiat_currency_specification : undefined
   return <Fragment>
     <div class="sm:hidden">
       <label for="tabs" class="sr-only"><i18n.Translate>Select a 
section</i18n.Translate></label>
@@ -135,7 +148,7 @@ function Metrics(): VNode {
     </div>
     <dl class="mt-5 grid grid-cols-1 md:grid-cols-2  divide-y divide-gray-200 
overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0">
 
-      {!fiatSpec || resp.current.body.type !== "with-conversions" || 
resp.previous.body.type !== "with-conversions" ? 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">
@@ -144,7 +157,7 @@ function Metrics(): VNode {
             <MetricValue
               current={resp.current.body.cashinFiatVolume}
               previous={resp.previous.body.cashinFiatVolume}
-              spec={fiatSpec}
+              spec={respInfo.body.fiat_currency_specification}
             />
           </div>
           <div class="px-4 py-5 sm:p-6">
@@ -154,7 +167,7 @@ function Metrics(): VNode {
             <MetricValue
               current={resp.current.body.cashoutFiatVolume}
               previous={resp.previous.body.cashoutFiatVolume}
-              spec={fiatSpec}
+              spec={respInfo.body.fiat_currency_specification}
             />
           </div>
         </Fragment>
diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx 
b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
index f9962fbde..a39a379de 100644
--- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx
+++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
@@ -120,6 +120,16 @@ export function CreateCashout({
   if (info instanceof TalerError) {
     return <ErrorLoadingWithDebug error={info} />
   }
+  if (info.type === "fail") {
+    switch (info.case) {
+      case HttpStatusCode.NotImplemented: {
+        return <Attention type="danger" title={i18n.str`Cashout not 
implemented`}>
+        </Attention>;
+      }
+      default: assertUnreachable(info.case)
+    }
+  }
+
 
   const conversionInfo = info.body.conversion_rate
   if (!conversionInfo) {
diff --git a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx 
b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
index a55bf3ab6..b4d5b6584 100644
--- a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
+++ b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
@@ -54,18 +54,13 @@ export function ShowCashoutDetails({
 }: Props): VNode {
   const { i18n, dateLocale } = useTranslationContext();
   const { state } = useBackendState();
-  const creds = state.status !== "loggedIn" ? undefined : state
-  const { api } = useBankCoreApiContext()
   const cid = Number.parseInt(id, 10)
 
   const result = useCashoutDetails(Number.isNaN(cid) ? undefined : cid);
-  const [code, setCode] = useState<string | undefined>(undefined);
-  const [notification, notify, handleError] = useLocalNotification()
   const info = useConversionInfo();
 
   if (Number.isNaN(cid)) {
-    //TODO: better error message
-    return <div>cashout id should be a number</div>
+    return <Attention type="danger" title={i18n.str`cashout id should be a 
number`} />
   }
   if (!result) {
     return <Loading />
@@ -89,116 +84,19 @@ export function ShowCashoutDetails({
   if (info instanceof TalerError) {
     return <ErrorLoadingWithDebug error={info} />
   }
-
-  const errors = undefinedIfEmpty({
-    code: !code ? i18n.str`required` : undefined,
-  });
-  /**
-   * @deprecated
-   */
-  const isPending = String(result.body.status).toUpperCase() === "PENDING";
-  const { fiat_currency_specification, regional_currency_specification } = 
info.body
-  // won't implement in retry in old API 3:0:3 since request_uid is missing
-  async function doAbortCashout() {
-    if (!creds) return;
-    await handleError(async () => {
-      const resp = await api.abortCashoutById(creds, cid);
-      if (resp.type === "ok") {
-        onCancel();
-      } else {
-        switch (resp.case) {
-          case HttpStatusCode.NotFound: return notify({
-            type: "error",
-            title: i18n.str`Cashout not found. It may be also mean that it was 
already aborted.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case HttpStatusCode.Conflict: return notify({
-            type: "error",
-            title: i18n.str`Cashout was already confimed.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case HttpStatusCode.NotImplemented: return notify({
-            type: "error",
-            title: i18n.str`Cashout operation is not supported.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          default: {
-            assertUnreachable(resp)
-          }
-        }
+  if (info.type === "fail") {
+    switch (info.case) {
+      case HttpStatusCode.NotImplemented: {
+        return <Attention type="danger" title={i18n.str`Cashout not 
implemented`} />
       }
-    })
-  }
-  async function doConfirmCashout() {
-    if (!creds || !code) return;
-    await handleError(async () => {
-      const resp = await api.confirmCashoutById(creds, cid, {
-        tan: code,
-      });
-      if (resp.type === "ok") {
-        mutate(() => true)//clean cashout state
-      } else {
-        switch (resp.case) {
-          case HttpStatusCode.NotFound: return notify({
-            type: "error",
-            title: i18n.str`Cashout not found. It may be also mean that it was 
already aborted.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({
-            type: "error",
-            title: i18n.str`The account does not have sufficient funds`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          });
-          case TalerErrorCode.BANK_BAD_CONVERSION: return notify({
-            type: "error",
-            title: i18n.str`The conversion rate was incorrectly applied`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          });
-          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return notify({
-            type: "error",
-            title: i18n.str`The cashout operation is already aborted.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          });
-          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return notify({
-            type: "error",
-            title: i18n.str`Missing destination account.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case HttpStatusCode.TooManyRequests: return notify({
-            type: "error",
-            title: i18n.str`Too many failed attempts.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case HttpStatusCode.NotImplemented: return notify({
-            type: "error",
-            title: i18n.str`Cashout operation is not supported.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED: return notify({
-            type: "error",
-            title: i18n.str`The code for this cashout is invalid.`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          default: assertUnreachable(resp)
-        }
-      }
-    })
+      default: assertUnreachable(info.case)
+    }
   }
 
+  const { fiat_currency_specification, regional_currency_specification } = 
info.body
+
   return (
     <div>
-      <LocalNotificationBanner notification={notification} />
       <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 
bg-gray-100 my-4 px-4 pb-4 rounded-lg">
 
         <section class="rounded-sm px-4">
@@ -208,16 +106,6 @@ export function ShowCashoutDetails({
               <dt class="text-sm 
text-gray-600"><i18n.Translate>Subject</i18n.Translate></dt>
               <dd class="text-sm ">{result.body.subject}</dd>
             </div>
-
-
-            <div class="flex items-center justify-between border-t-2 afu pt-4">
-              <dt class="flex items-center text-sm text-gray-600">
-                <span><i18n.Translate>Status</i18n.Translate></span>
-              </dt>
-              <dd data-status={result.body.status} class="text-sm uppercase 
data-[status=pending]:text-yellow-600 data-[status=aborted]:text-red-600 
data-[status=confirmed]:text-green-600" >
-                {result.body.status}
-              </dd>
-            </div>
           </dl>
         </section>
         <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl 
md:col-span-2">
@@ -252,14 +140,6 @@ export function ShowCashoutDetails({
                     </dd>
                   </div>
 
-                  {result.body.confirmation_time && 
result.body.confirmation_time.t_s !== "never" ?
-                    <div class="flex justify-between items-center border-t-2 
afu pt-4">
-                      <dt class="  
font-medium"><i18n.Translate>Confirmed</i18n.Translate></dt>
-                      <dd class="  font-medium">
-                        {format(result.body.confirmation_time.t_s * 1000, 
"dd/MM/yyyy HH:mm:ss", { locale: dateLocale })}
-                      </dd>
-                    </div>
-                    : undefined}
                 </dl>
               </div>
             </div>
@@ -267,61 +147,6 @@ export function ShowCashoutDetails({
 
         </div>
 
-        {!isPending ? undefined :
-          <Fragment>
-            <div />
-            <form
-              class="bg-white shadow-sm ring-1 ring-gray-900/5"
-              autoCapitalize="none"
-              autoCorrect="off"
-              onSubmit={e => {
-                e.preventDefault()
-              }}
-            >
-              <div class="px-4 py-6 sm:p-8">
-                <label for="withdraw-amount">
-                  <i18n.Translate>Enter the confirmation code</i18n.Translate>
-                </label>
-                <div class="mt-2">
-                  <div class="relative rounded-md shadow-sm">
-                    <input
-                      type="text"
-                      // class="block w-full rounded-md border-0 py-1.5 pl-16 
text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 
focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-                      aria-describedby="answer"
-                      autoFocus
-                      class="block w-full rounded-md border-0 py-1.5 
text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 
placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 
sm:text-sm sm:leading-6"
-                      value={code ?? ""}
-                      required
-
-                      name="answer"
-                      id="answer"
-                      autocomplete="off"
-                      onChange={(e): void => {
-                        setCode(e.currentTarget.value)
-                      }}
-                    />
-                  </div>
-                  <ShowInputErrorLabel message={errors?.code} isDirty={code 
!== undefined} />
-                </div>
-              </div>
-              <div class="flex items-center justify-between gap-x-6 border-t 
border-gray-900/10 px-4 py-4 sm:px-8">
-                <button type="button"
-                  class="inline-flex items-center rounded-md bg-red-600 px-3 
py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 
focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 
focus-visible:outline-red-500"
-                  onClick={doAbortCashout}
-                >
-                  <i18n.Translate>Abort</i18n.Translate></button>
-                <button type="submit"
-                  class="disabled:opacity-50 disabled:cursor-default 
cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold 
text-white shadow-sm hover:bg-indigo-500 focus-visible:outline 
focus-visible:outline-2 focus-visible:outline-offset-2 
focus-visible:outline-indigo-600"
-                  disabled={!!errors}
-                  onClick={(e) => {
-                    doConfirmCashout()
-                  }}
-                >
-                  <i18n.Translate>Confirm</i18n.Translate>
-                </button>
-              </div>
-            </form>
-          </Fragment>}
       </div>
 
       <br />
diff --git a/packages/taler-util/src/http-client/authentication.ts 
b/packages/taler-util/src/http-client/authentication.ts
index b27a266e9..66e00ded5 100644
--- a/packages/taler-util/src/http-client/authentication.ts
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -17,7 +17,7 @@
 import { HttpStatusCode } from "../http-status-codes.js";
 import { HttpRequestLibrary, createPlatformHttpLib, makeBasicAuthHeader } from 
"../http.js";
 import { LibtoolVersion } from "../libtool-version.js";
-import { opEmptySuccess, opKnownFailure, opSuccess, opUnknownFailure } from 
"../operation.js";
+import { opEmptySuccess, opKnownHttpFailure, opSuccess, opUnknownFailure } 
from "../operation.js";
 import { AccessToken, TalerAuthentication, codecForTokenSuccessResponse } from 
"./types.js";
 import { makeBearerTokenAuthHeader } from "./utils.js";
 
@@ -59,8 +59,8 @@ export class TalerAuthenticationHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForTokenSuccessResponse())
       //FIXME: missing in docs
-      case HttpStatusCode.Unauthorized: return 
opKnownFailure("wrong-credentials", resp)
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp)
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -76,7 +76,7 @@ export class TalerAuthenticationHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opEmptySuccess()
       //FIXME: missing in docs
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
diff --git a/packages/taler-util/src/http-client/bank-conversion.ts 
b/packages/taler-util/src/http-client/bank-conversion.ts
index 2bc9fdb79..3ecb036ee 100644
--- a/packages/taler-util/src/http-client/bank-conversion.ts
+++ b/packages/taler-util/src/http-client/bank-conversion.ts
@@ -2,13 +2,13 @@ import { AmountJson, Amounts } from "../amounts.js";
 import { HttpRequestLibrary } from "../http-common.js";
 import { HttpStatusCode } from "../http-status-codes.js";
 import { createPlatformHttpLib } from "../http.js";
-import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opKnownFailure, 
opSuccess, opUnknownFailure } from "../operation.js";
+import { LibtoolVersion } from "../libtool-version.js";
+import { FailCasesByMethod, ResultByMethod, opEmptySuccess, 
opKnownHttpFailure, opSuccess, opUnknownFailure } from "../operation.js";
 import { TalerErrorCode } from "../taler-error-codes.js";
 import { codecForTalerErrorDetail } from "../wallet-types.js";
 import {
   AccessToken,
   TalerBankConversionApi,
-  UserAndToken,
   codecForCashinConversionResponse,
   codecForCashoutConversionResponse,
   codecForConversionBankConfig
@@ -22,6 +22,8 @@ export type TalerBankConversionErrorsByMethod<prop extends 
keyof TalerBankConver
  * The API is used by the wallets.
  */
 export class TalerBankConversionHttpClient {
+  public readonly PROTOCOL_VERSION = "0:0:0";
+
   httpLib: HttpRequestLibrary;
 
   constructor(
@@ -31,6 +33,11 @@ export class TalerBankConversionHttpClient {
     this.httpLib = httpClient ?? createPlatformHttpLib();
   }
 
+  isCompatible(version: string): boolean {
+    const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
+    return compare?.compatible ?? false
+  }
+
   /**
    * https://docs.taler.net/core/api-bank-conversion-info.html#get--config
    * 
@@ -42,6 +49,7 @@ export class TalerBankConversionHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForConversionBankConfig())
+      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp)
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -67,14 +75,14 @@ export class TalerBankConversionHttpClient {
         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);
+          case TalerErrorCode.GENERIC_PARAMETER_MISSING: return 
opKnownHttpFailure(resp.status, resp);
+          case TalerErrorCode.GENERIC_PARAMETER_MALFORMED: return 
opKnownHttpFailure(resp.status, resp);
+          case TalerErrorCode.GENERIC_CURRENCY_MISMATCH: return 
opKnownHttpFailure(resp.status, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
-      case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", 
resp);
-      case HttpStatusCode.NotImplemented: return 
opKnownFailure("conversion-not-supported", resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -100,14 +108,14 @@ export class TalerBankConversionHttpClient {
         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);
+          case TalerErrorCode.GENERIC_PARAMETER_MISSING: return 
opKnownHttpFailure(resp.status, resp);
+          case TalerErrorCode.GENERIC_PARAMETER_MALFORMED: return 
opKnownHttpFailure(resp.status, resp);
+          case TalerErrorCode.GENERIC_CURRENCY_MISMATCH: return 
opKnownHttpFailure(resp.status, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
-      case HttpStatusCode.Conflict: return opKnownFailure("amount-too-small", 
resp);
-      case HttpStatusCode.NotImplemented: return 
opKnownFailure("conversion-not-supported", resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -127,8 +135,8 @@ export class TalerBankConversionHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotImplemented: return 
opKnownFailure("conversion-not-supported", resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index dbb6c7112..8a3283d0f 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -17,6 +17,7 @@
 import {
   HttpStatusCode,
   LibtoolVersion,
+  LongPollParams,
   TalerErrorCode,
   codecForChallenge,
   codecForTalerErrorDetail,
@@ -29,22 +30,26 @@ import {
   HttpRequestLibrary,
   createPlatformHttpLib
 } from "@gnu-taler/taler-util/http";
-import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, 
opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js";
+import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, 
opSuccess, opUnknownFailure } from "../operation.js";
 import { TalerAuthenticationHttpClient } from "./authentication.js";
 import { TalerBankConversionHttpClient } from "./bank-conversion.js";
 import { TalerBankIntegrationHttpClient } from "./bank-integration.js";
 import { TalerRevenueHttpClient } from "./bank-revenue.js";
 import { TalerWireGatewayHttpClient } from "./bank-wire.js";
 import { AccessToken, PaginationParams, TalerCorebankApi, UserAndToken, 
WithdrawalOperationStatus, codecForAccountData, 
codecForBankAccountCreateWithdrawalResponse, 
codecForBankAccountTransactionInfo, codecForBankAccountTransactionsResponse, 
codecForCashoutPending, codecForCashoutStatusResponse, codecForCashouts, 
codecForCoreBankConfig, codecForCreateTransactionResponse, 
codecForGlobalCashouts, codecForListBankAccountsResponse, 
codecForMonitorResponse, codecForPublicAccountsResponse, cod [...]
-import { addPaginationParams, makeBearerTokenAuthHeader } from "./utils.js";
+import { addLongPollingParam, addPaginationParams, makeBearerTokenAuthHeader } 
from "./utils.js";
 
 
 export type TalerCoreBankResultByMethod<prop extends keyof 
TalerCoreBankHttpClient> = ResultByMethod<TalerCoreBankHttpClient, prop>
 export type TalerCoreBankErrorsByMethod<prop extends keyof 
TalerCoreBankHttpClient> = FailCasesByMethod<TalerCoreBankHttpClient, prop>
 
 /**
- * Protocol version spoken with the bank.
+ * Protocol version spoken with the core bank.
  *
+ * Endpoint must be ordered in the same way that in the docs
+ * Response code (http and taler) must have the same order that in the docs
+ * That way is easier to see changes
+ * 
  * Uses libtool's current:revision:age versioning.
  */
 export class TalerCoreBankHttpClient {
@@ -134,8 +139,8 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Conflict: {
         const body = await resp.json()
         const details = codecForTalerErrorDetail().decode(body)
@@ -166,17 +171,17 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Conflict: {
         const body = await resp.json()
         const details = codecForTalerErrorDetail().decode(body)
         switch (details.code) {
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_MISSING_TAN_INFO: return 
opKnownTalerFailure(details.code, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
@@ -289,9 +294,10 @@ export class TalerCoreBankHttpClient {
    * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-transactions
    * 
    */
-  async getTransactions(auth: UserAndToken, pagination?: PaginationParams) {
+  async getTransactions(auth: UserAndToken, params?: PaginationParams & 
LongPollParams) {
     const url = new URL(`accounts/${auth.username}/transactions`, 
this.baseUrl);
-    addPaginationParams(url, pagination)
+    addPaginationParams(url, params)
+    addLongPollingParam(url, params)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -342,8 +348,8 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCreateTransactionResponse())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
@@ -382,62 +388,63 @@ export class TalerCoreBankHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankAccountCreateWithdrawalResponse())
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
+      //FIXME: missing in docs
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
    * 
    */
-  async abortWithdrawalById(auth: UserAndToken, wid: string) {
-    const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/abort`, 
this.baseUrl);
+  async confirmWithdrawalById(auth: UserAndToken, wid: string, cid?: string) {
+    const url = new 
URL(`accounts/${auth.username}/withdrawals/${wid}/confirm`, this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
       headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token)
+        Authorization: makeBearerTokenAuthHeader(auth.token),
+        "X-Challenge-Id": cid,
       },
     });
     switch (resp.status) {
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp)
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
-      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: {
+        const body = await resp.json()
+        const details = codecForTalerErrorDetail().decode(body)
+        switch (details.code) {
+          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownTalerFailure(details.code, resp);
+          default: return opUnknownFailure(resp, body)
+        }
+      }
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
 
   /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-confirm
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-withdrawals-$WITHDRAWAL_ID-abort
    * 
    */
-  async confirmWithdrawalById(auth: UserAndToken, wid: string, cid?: string) {
-    const url = new 
URL(`accounts/${auth.username}/withdrawals/${wid}/confirm`, this.baseUrl);
+  async abortWithdrawalById(auth: UserAndToken, wid: string) {
+    const url = new URL(`accounts/${auth.username}/withdrawals/${wid}/abort`, 
this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
       method: "POST",
       headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token),
-        "X-Challenge-Id": cid,
+        Authorization: makeBearerTokenAuthHeader(auth.token)
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp)
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
-      case HttpStatusCode.Conflict: {
-        const body = await resp.json()
-        const details = codecForTalerErrorDetail().decode(body)
-        switch (details.code) {
-          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownTalerFailure(details.code, resp);
-          default: return opUnknownFailure(resp, body)
-        }
-      }
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -446,14 +453,13 @@ export class TalerCoreBankHttpClient {
    * 
https://docs.taler.net/core/api-corebank.html#get--withdrawals-$WITHDRAWAL_ID
    * 
    */
-  async getWithdrawalById(wid: string, wait?: {
+  async getWithdrawalById(wid: string, params?: {
     old_state?: WithdrawalOperationStatus,
-    timeoutMs: number
-  }) {
+  } & LongPollParams) {
     const url = new URL(`withdrawals/${wid}`, this.baseUrl);
-    if (wait) {
-      url.searchParams.set("long_poll_ms", String(wait.timeoutMs))
-      url.searchParams.set("old_state", !wait.old_state ? "pending" : 
wait.old_state)
+    addLongPollingParam(url, params)
+    if (params) {
+      url.searchParams.set("old_state", !params.old_state ? "pending" : 
params.old_state)
     }
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
@@ -486,8 +492,8 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.Ok: return opSuccess(resp, codecForCashoutPending())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       case HttpStatusCode.Conflict: {
         const body = await resp.json()
@@ -513,61 +519,6 @@ export class TalerCoreBankHttpClient {
     }
   }
 
-  /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-abort
-   * @deprecated since 4
-   */
-  async abortCashoutById(auth: UserAndToken, cid: number) {
-    const url = new URL(`accounts/${auth.username}/cashouts/${cid}/abort`, 
this.baseUrl);
-    const resp = await this.httpLib.fetch(url.href, {
-      method: "POST",
-      headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token)
-      },
-    });
-    switch (resp.status) {
-      case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
-      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
-      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
-      default: return opUnknownFailure(resp, await resp.text())
-    }
-  }
-
-  /**
-   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-cashouts-$CASHOUT_ID-confirm
-   * @deprecated since 4
-   */
-  async confirmCashoutById(auth: UserAndToken, cid: number, body: 
TalerCorebankApi.CashoutConfirmRequest) {
-    const url = new URL(`accounts/${auth.username}/cashouts/${cid}/confirm`, 
this.baseUrl);
-    const resp = await this.httpLib.fetch(url.href, {
-      method: "POST",
-      headers: {
-        Authorization: makeBearerTokenAuthHeader(auth.token)
-      },
-      body,
-    });
-    switch (resp.status) {
-      case HttpStatusCode.NoContent: return opEmptySuccess()
-      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
-      case HttpStatusCode.Conflict: {
-        const body = await resp.json()
-        const details = codecForTalerErrorDetail().decode(body)
-        switch (details.code) {
-          case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_BAD_CONVERSION: return 
opKnownTalerFailure(details.code, resp);
-          case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED: return 
opKnownTalerFailure(details.code, resp);
-          default: return opUnknownFailure(resp, body)
-        }
-      }
-      case HttpStatusCode.TooManyRequests: return 
opKnownHttpFailure(resp.status, resp);
-      case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
-      default: return opUnknownFailure(resp, await resp.text())
-    }
-  }
-
   /**
    * 
https://docs.taler.net/core/api-corebank.html#get--accounts-$USERNAME-cashouts-$CASHOUT_ID
    * 
@@ -604,7 +555,6 @@ export class TalerCoreBankHttpClient {
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForCashouts())
       case HttpStatusCode.NoContent: return opFixedSuccess({ cashouts: [] });
-      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);;
       case HttpStatusCode.NotImplemented: return 
opKnownHttpFailure(resp.status, resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
@@ -632,41 +582,13 @@ export class TalerCoreBankHttpClient {
   }
 
   //
-  // MONITOR
+  // 2FA
   //
 
   /**
-   * https://docs.taler.net/core/api-corebank.html#get--monitor
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID
    * 
    */
-  async getMonitor(auth: AccessToken, params: { timeframe?: 
TalerCorebankApi.MonitorTimeframeParam, which?: number } = {}) {
-    const url = new URL(`monitor`, this.baseUrl);
-    if (params.timeframe) {
-      url.searchParams.set("timeframe", 
TalerCorebankApi.MonitorTimeframeParam[params.timeframe])
-    }
-    if (params.which) {
-      url.searchParams.set("which", String(params.which))
-    }
-    const resp = await this.httpLib.fetch(url.href, {
-      method: "GET",
-      headers: {
-        Authorization: makeBearerTokenAuthHeader(auth)
-      },
-    });
-    switch (resp.status) {
-      case HttpStatusCode.Ok: return opSuccess(resp, codecForMonitorResponse())
-      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
-      //FIXME remove when server is updated
-      //FIXME: should be 404 ?
-      case HttpStatusCode.ServiceUnavailable: return 
opKnownHttpFailure(resp.status, resp);
-      default: return opUnknownFailure(resp, await resp.text())
-    }
-  }
-
-  //
-  // 2FA
-  //
   async sendChallenge(auth: UserAndToken, cid: string) {
     const url = new URL(`accounts/${auth.username}/challenge/${cid}`, 
this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
@@ -691,6 +613,10 @@ export class TalerCoreBankHttpClient {
     }
   }
 
+  /**
+   * 
https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-challenge-$CHALLENGE_ID-confirm
+   * 
+   */
   async confirmChallenge(auth: UserAndToken, cid: string, body: 
TalerCorebankApi.ChallengeSolve) {
     const url = new URL(`accounts/${auth.username}/challenge/${cid}/confirm`, 
this.baseUrl);
     const resp = await this.httpLib.fetch(url.href, {
@@ -718,6 +644,36 @@ export class TalerCoreBankHttpClient {
     }
   }
 
+  //
+  // MONITOR
+  //
+
+  /**
+   * https://docs.taler.net/core/api-corebank.html#get--monitor
+   * 
+   */
+  async getMonitor(auth: AccessToken, params: { timeframe?: 
TalerCorebankApi.MonitorTimeframeParam, which?: number } = {}) {
+    const url = new URL(`monitor`, this.baseUrl);
+    if (params.timeframe) {
+      url.searchParams.set("timeframe", 
TalerCorebankApi.MonitorTimeframeParam[params.timeframe])
+    }
+    if (params.which) {
+      url.searchParams.set("which", String(params.which))
+    }
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "GET",
+      headers: {
+        Authorization: makeBearerTokenAuthHeader(auth)
+      },
+    });
+    switch (resp.status) {
+      case HttpStatusCode.Ok: return opSuccess(resp, codecForMonitorResponse())
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
+    }
+  }
+
 
   //
   // Others API
diff --git a/packages/taler-util/src/http-client/bank-integration.ts 
b/packages/taler-util/src/http-client/bank-integration.ts
index 757f1f897..2264b65bf 100644
--- a/packages/taler-util/src/http-client/bank-integration.ts
+++ b/packages/taler-util/src/http-client/bank-integration.ts
@@ -2,16 +2,18 @@ import { HttpRequestLibrary, readSuccessResponseJsonOrThrow } 
from "../http-comm
 import { HttpStatusCode } from "../http-status-codes.js";
 import { createPlatformHttpLib } from "../http.js";
 import { LibtoolVersion } from "../libtool-version.js";
-import { FailCasesByMethod, ResultByMethod, opKnownFailure, opSuccess, 
opUnknownFailure } from "../operation.js";
+import { FailCasesByMethod, ResultByMethod, opEmptySuccess, 
opKnownHttpFailure, opKnownTalerFailure, opSuccess, opUnknownFailure } from 
"../operation.js";
 import { TalerErrorCode } from "../taler-error-codes.js";
 import { codecForTalerErrorDetail } from "../wallet-types.js";
 import {
+  LongPollParams,
   TalerBankIntegrationApi,
   WithdrawalOperationStatus,
   codecForBankWithdrawalOperationPostResponse,
   codecForBankWithdrawalOperationStatus,
   codecForIntegrationBankConfig
 } from "./types.js";
+import { addLongPollingParam } from "./utils.js";
 
 export type TalerBankIntegrationResultByMethod<prop extends keyof 
TalerBankIntegrationHttpClient> = 
ResultByMethod<TalerBankIntegrationHttpClient, prop>
 export type TalerBankIntegrationErrorsByMethod<prop extends keyof 
TalerBankIntegrationHttpClient> = 
FailCasesByMethod<TalerBankIntegrationHttpClient, prop>
@@ -20,7 +22,7 @@ export type TalerBankIntegrationErrorsByMethod<prop extends 
keyof TalerBankInteg
  * The API is used by the wallets.
  */
 export class TalerBankIntegrationHttpClient {
-  public readonly PROTOCOL_VERSION = "3:0:3";
+  public readonly PROTOCOL_VERSION = "2:0:2";
 
   httpLib: HttpRequestLibrary;
 
@@ -55,21 +57,20 @@ export class TalerBankIntegrationHttpClient {
    * 
https://docs.taler.net/core/api-bank-integration.html#get--withdrawal-operation-$WITHDRAWAL_ID
    * 
    */
-  async getWithdrawalOperationById(woid: string, wait?: {
-    old_state?: WithdrawalOperationStatus,
-    timeoutMs: number
-  }) {
+  async getWithdrawalOperationById(woid: string, params?: {
+    old_state?: WithdrawalOperationStatus
+  } & LongPollParams) {
     const url = new URL(`withdrawal-operation/${woid}`, this.baseUrl);
-    if (wait) {
-      url.searchParams.set("long_poll_ms", String(wait.timeoutMs))
-      url.searchParams.set("old_state", !wait.old_state ? "pending" : 
wait.old_state)
+    addLongPollingParam(url, params)
+    if (params) {
+      url.searchParams.set("old_state", !params.old_state ? "pending" : 
params.old_state)
     }
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET"
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankWithdrawalOperationStatus())
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -86,15 +87,15 @@ export class TalerBankIntegrationHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForBankWithdrawalOperationPostResponse())
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp)
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       case HttpStatusCode.Conflict: {
         const body = await resp.json()
         const details = codecForTalerErrorDetail().decode(body)
         switch (details.code) {
-          case 
TalerErrorCode.BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT: return 
opKnownFailure("already-selected", resp);
-          case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT: return 
opKnownFailure("duplicated-reserve-id", resp);
-          case TalerErrorCode.BANK_UNKNOWN_ACCOUNT: return 
opKnownFailure("account-not-found", resp);
-          case TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE: return 
opKnownFailure("account-not-exchange", resp);
+          case 
TalerErrorCode.BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_DUPLICATE_RESERVE_PUB_SUBJECT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_UNKNOWN_ACCOUNT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE: return 
opKnownTalerFailure(details.code, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
@@ -102,5 +103,21 @@ export class TalerBankIntegrationHttpClient {
     }
   }
 
+  /**
+   * 
https://docs.taler.net/core/api-bank-integration.html#post-$BANK_API_BASE_URL-withdrawal-operation-$wopid
+   * 
+   */
+  async abortWithdrawalOperationById(woid: string) {
+    const url = new URL(`withdrawal-operation/${woid}/abort`, this.baseUrl);
+    const resp = await this.httpLib.fetch(url.href, {
+      method: "POST",
+    });
+    switch (resp.status) {
+      case HttpStatusCode.NoContent: return opEmptySuccess()
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
+      default: return opUnknownFailure(resp, await resp.text())
+    }
+  }
 }
 
diff --git a/packages/taler-util/src/http-client/bank-revenue.ts 
b/packages/taler-util/src/http-client/bank-revenue.ts
index 040ad8dd2..9dfcc4f64 100644
--- a/packages/taler-util/src/http-client/bank-revenue.ts
+++ b/packages/taler-util/src/http-client/bank-revenue.ts
@@ -1,9 +1,9 @@
 import { HttpRequestLibrary, makeBasicAuthHeader, 
readSuccessResponseJsonOrThrow } from "../http-common.js";
 import { HttpStatusCode } from "../http-status-codes.js";
 import { createPlatformHttpLib } from "../http.js";
-import { FailCasesByMethod, ResultByMethod, opKnownFailure, opSuccess, 
opUnknownFailure } from "../operation.js";
-import { PaginationParams, TalerRevenueApi, codecForMerchantIncomingHistory } 
from "./types.js";
-import { addPaginationParams } from "./utils.js";
+import { FailCasesByMethod, ResultByMethod, opKnownHttpFailure, opSuccess, 
opUnknownFailure } from "../operation.js";
+import { LongPollParams, PaginationParams, TalerRevenueApi, 
codecForMerchantIncomingHistory } from "./types.js";
+import { addLongPollingParam, addPaginationParams } from "./utils.js";
 
 export type TalerBankRevenueResultByMethod<prop extends keyof 
TalerRevenueHttpClient> = ResultByMethod<TalerRevenueHttpClient, prop>
 export type TalerBankRevenueErrorsByMethod<prop extends keyof 
TalerRevenueHttpClient> = FailCasesByMethod<TalerRevenueHttpClient, prop>
@@ -22,15 +22,37 @@ export class TalerRevenueHttpClient {
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
   }
+  // public readonly PROTOCOL_VERSION = "4:0:0";
+  // isCompatible(version: string): boolean {
+  //   const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
+  //   return compare?.compatible ?? false
+  // }
+
+  // /**
+  //  * https://docs.taler.net/core/api-corebank.html#config
+  //  * 
+  //  */
+  // async getConfig() {
+  //   const url = new URL(`config`, this.baseUrl);
+  //   const resp = await this.httpLib.fetch(url.href, {
+  //     method: "GET"
+  //   });
+  //   switch (resp.status) {
+  //     case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCoreBankConfig())
+  //     default: return opUnknownFailure(resp, await resp.text())
+  //   }
+  // }
+
 
   /**
    * https://docs.taler.net/core/api-bank-revenue.html#get--history
    * 
    * @returns 
    */
-  async getHistory(auth: string, pagination?: PaginationParams) {
+  async getHistory(auth: string, params?: PaginationParams & LongPollParams) {
     const url = new URL(`history`, this.baseUrl);
-    addPaginationParams(url, pagination)
+    addPaginationParams(url, params)
+    addLongPollingParam(url, params)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -39,9 +61,9 @@ export class TalerRevenueHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForMerchantIncomingHistory())
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return 
opKnownFailure("endpoint-wrong-or-username-wrong", resp);
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
diff --git a/packages/taler-util/src/http-client/bank-wire.ts 
b/packages/taler-util/src/http-client/bank-wire.ts
index 7e3c00637..90c3aeae5 100644
--- a/packages/taler-util/src/http-client/bank-wire.ts
+++ b/packages/taler-util/src/http-client/bank-wire.ts
@@ -1,9 +1,9 @@
 import { HttpRequestLibrary, makeBasicAuthHeader } from "../http-common.js";
 import { HttpStatusCode } from "../http-status-codes.js";
 import { createPlatformHttpLib } from "../http.js";
-import { FailCasesByMethod, ResultByMethod, opFixedSuccess, opKnownFailure, 
opSuccess, opUnknownFailure } from "../operation.js";
-import { PaginationParams, TalerWireGatewayApi, codecForAddIncomingResponse, 
codecForIncomingHistory, codecForOutgoingHistory, codecForTransferResponse } 
from "./types.js";
-import { addPaginationParams } from "./utils.js";
+import { FailCasesByMethod, ResultByMethod, opFixedSuccess, 
opKnownHttpFailure, opSuccess, opUnknownFailure } from "../operation.js";
+import { LongPollParams, PaginationParams, TalerWireGatewayApi, 
codecForAddIncomingResponse, codecForIncomingHistory, codecForOutgoingHistory, 
codecForTransferResponse } from "./types.js";
+import { addLongPollingParam, addPaginationParams } from "./utils.js";
 
 export type TalerWireGatewayResultByMethod<prop extends keyof 
TalerWireGatewayHttpClient> = ResultByMethod<TalerWireGatewayHttpClient, prop>
 export type TalerWireGatewayErrorsByMethod<prop extends keyof 
TalerWireGatewayHttpClient> = FailCasesByMethod<TalerWireGatewayHttpClient, 
prop>
@@ -25,6 +25,27 @@ export class TalerWireGatewayHttpClient {
   ) {
     this.httpLib = httpClient ?? createPlatformHttpLib();
   }
+  // public readonly PROTOCOL_VERSION = "4:0:0";
+  // isCompatible(version: string): boolean {
+  //   const compare = LibtoolVersion.compare(this.PROTOCOL_VERSION, version)
+  //   return compare?.compatible ?? false
+  // }
+
+  // /**
+  //  * https://docs.taler.net/core/api-corebank.html#config
+  //  * 
+  //  */
+  // async getConfig() {
+  //   const url = new URL(`config`, this.baseUrl);
+  //   const resp = await this.httpLib.fetch(url.href, {
+  //     method: "GET"
+  //   });
+  //   switch (resp.status) {
+  //     case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCoreBankConfig())
+  //     default: return opUnknownFailure(resp, await resp.text())
+  //   }
+  // }
+
 
   /**
    * https://docs.taler.net/core/api-bank-wire.html#post--transfer
@@ -42,10 +63,12 @@ export class TalerWireGatewayHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForTransferResponse())
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      case HttpStatusCode.Conflict: return 
opKnownFailure("request-uid-already-used", resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -54,9 +77,10 @@ export class TalerWireGatewayHttpClient {
    * https://docs.taler.net/core/api-bank-wire.html#get--history-incoming
    * 
    */
-  async getHistoryIncoming(auth: string, pagination?: PaginationParams) {
+  async getHistoryIncoming(auth: string, params?: PaginationParams & 
LongPollParams) {
     const url = new URL(`history/incoming`, this.baseUrl);
-    addPaginationParams(url, pagination)
+    addPaginationParams(url, params)
+    addLongPollingParam(url, params)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -65,22 +89,25 @@ export class TalerWireGatewayHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForIncomingHistory())
-      case HttpStatusCode.NoContent: return opFixedSuccess({ 
incoming_transactions: [] })
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      //FIXME: account should not be returned or make it optional
+      case HttpStatusCode.NoContent: return opFixedSuccess({ 
incoming_transactions: [], credit_account: undefined })
+      //FIXME: show more details in docs
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
-    // return readSuccessResponseJsonOrThrow(resp, codecForIncomingHistory());
   }
 
   /**
    * https://docs.taler.net/core/api-bank-wire.html#get--history-outgoing
    * 
    */
-  async getHistoryOutgoing(auth: string, pagination?: PaginationParams) {
+  async getHistoryOutgoing(auth: string, params?: PaginationParams & 
LongPollParams) {
     const url = new URL(`history/outgoing`, this.baseUrl);
-    addPaginationParams(url, pagination)
+    addPaginationParams(url, params)
+    addLongPollingParam(url, params)
     const resp = await this.httpLib.fetch(url.href, {
       method: "GET",
       headers: {
@@ -89,10 +116,13 @@ export class TalerWireGatewayHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForOutgoingHistory())
-      case HttpStatusCode.NoContent: return opFixedSuccess({ 
outgoing_transactions: [] })
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
+      //FIXME: account should not be returned or make it optional
+      case HttpStatusCode.NoContent: return opFixedSuccess({ 
outgoing_transactions: [], debit_account: undefined })
+      //FIXME: show more details in docs
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -112,10 +142,12 @@ export class TalerWireGatewayHttpClient {
     });
     switch (resp.status) {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForAddIncomingResponse())
-      case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("not-found", resp);
-      case HttpStatusCode.Conflict: return 
opKnownFailure("reserve-id-already-used", resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      //FIXME: show more details in docs
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
diff --git a/packages/taler-util/src/http-client/exchange.ts 
b/packages/taler-util/src/http-client/exchange.ts
index f55be0043..36adb5a1a 100644
--- a/packages/taler-util/src/http-client/exchange.ts
+++ b/packages/taler-util/src/http-client/exchange.ts
@@ -3,7 +3,7 @@ import { HttpStatusCode } from "../http-status-codes.js";
 import { createPlatformHttpLib } from "../http.js";
 import { LibtoolVersion } from "../libtool-version.js";
 import { hash } from "../nacl-fast.js";
-import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, 
opKnownFailure, opSuccess, opUnknownFailure } from "../operation.js";
+import { FailCasesByMethod, ResultByMethod, opEmptySuccess, opFixedSuccess, 
opKnownHttpFailure, opSuccess, opUnknownFailure } from "../operation.js";
 import { TalerSignaturePurpose, amountToBuffer, bufferForUint32, buildSigPS, 
decodeCrock, eddsaSign, encodeCrock, stringToBytes, timestampRoundedToBuffer } 
from "../taler-crypto.js";
 import { OfficerAccount, PaginationParams, SigningKey, TalerExchangeApi, 
codecForAmlDecisionDetails, codecForAmlRecords, codecForExchangeConfig } from 
"./types.js";
 import { addPaginationParams } from "./utils.js";
@@ -15,7 +15,7 @@ export type TalerExchangeErrorsByMethod<prop extends keyof 
TalerExchangeHttpClie
  */
 export class TalerExchangeHttpClient {
   httpLib: HttpRequestLibrary;
-  public readonly PROTOCOL_VERSION = "17:0:0";
+  public readonly PROTOCOL_VERSION = "18:0:1";
 
   constructor(
     readonly baseUrl: string,
@@ -43,6 +43,9 @@ export class TalerExchangeHttpClient {
     }
   }
 
+  // TERMS
+
+
   //
   // AML operations
   //
@@ -66,10 +69,10 @@ export class TalerExchangeHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, codecForAmlRecords())
       case HttpStatusCode.NoContent: return opFixedSuccess({ records: [] })
       //this should be unauthorized
-      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("officer-not-found", 
resp);
-      case HttpStatusCode.Conflict: return opKnownFailure("officer-disabled", 
resp);
+      case HttpStatusCode.Forbidden: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -92,10 +95,10 @@ export class TalerExchangeHttpClient {
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForAmlDecisionDetails())
       case HttpStatusCode.NoContent: return opFixedSuccess({ aml_history: [], 
kyc_attributes: [] })
       //this should be unauthorized
-      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.NotFound: return opKnownFailure("officer-not-found", 
resp);
-      case HttpStatusCode.Conflict: return opKnownFailure("officer-disabled", 
resp);
+      case HttpStatusCode.Forbidden: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
@@ -116,11 +119,11 @@ export class TalerExchangeHttpClient {
     switch (resp.status) {
       case HttpStatusCode.NoContent: return opEmptySuccess()
       //FIXME: this should be unauthorized
-      case HttpStatusCode.Forbidden: return opKnownFailure("unauthorized", 
resp);
-      case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", 
resp);
+      case HttpStatusCode.Forbidden: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
       //FIXME: this two need to be splitted by error code
-      case HttpStatusCode.NotFound: return 
opKnownFailure("officer-or-account-not-found", resp);
-      case HttpStatusCode.Conflict: return 
opKnownFailure("officer-disabled-or-recent-decision", resp);
+      case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
+      case HttpStatusCode.Conflict: return opKnownHttpFailure(resp.status, 
resp);
       default: return opUnknownFailure(resp, await resp.text())
     }
   }
diff --git a/packages/taler-util/src/http-client/merchant.ts 
b/packages/taler-util/src/http-client/merchant.ts
index a6dc4661f..f8d6a4cff 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -12,7 +12,7 @@ export type TalerMerchantErrorsByMethod<prop extends keyof 
TalerMerchantHttpClie
  */
 export class TalerMerchantHttpClient {
   httpLib: HttpRequestLibrary;
-  public readonly PROTOCOL_VERSION = "5:0:1";
+  public readonly PROTOCOL_VERSION = "6:0:2";
 
   constructor(
     readonly baseUrl: string,
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index 75241aa30..2172eee39 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -53,16 +53,18 @@ export type PaginationParams = {
    * always greater than 0
    */
   limit?: number;
-  /**
-   * milliseconds the server should wait for at least one result to be shown
-   */
-  timoutMs?: number;
   /**
    * order
    */
   order: "asc" | "dec";
 };
 
+export type LongPollParams = {
+  /**
+   * milliseconds the server should wait for at least one result to be shown
+   */
+  timeoutMs?: number;
+};
 ///
 /// HASH
 ///
@@ -273,13 +275,13 @@ export const codecForCoreBankConfig = (): 
Codec<TalerCorebankApi.Config> =>
     .property("name", codecForConstString("libeufin-bank"))
     .property("version", codecForString())
     .property("allow_conversion", codecForBoolean())
-    .property("allow_deletions", codecForBoolean())
     .property("allow_registrations", codecForBoolean())
-    .property("allow_edit_cashout_payto_uri", codecForBoolean())
+    .property("allow_deletions", codecForBoolean())
     .property("allow_edit_name", codecForBoolean())
+    .property("allow_edit_cashout_payto_uri", codecForBoolean())
     .property("default_debit_threshold", codecForAmountString())
-    .property("currency_specification", codecForCurrencySpecificiation())
     .property("currency", codecForString())
+    .property("currency_specification", codecForCurrencySpecificiation())
     .property("supported_tan_channels", codecForList(codecForEither(
       codecForConstString(TalerCorebankApi.TanChannel.SMS),
       codecForConstString(TalerCorebankApi.TanChannel.EMAIL),
@@ -334,10 +336,11 @@ export const codecForPublicAccountsResponse =
 export const codecForAccountMinimalData =
   (): Codec<TalerCorebankApi.AccountMinimalData> =>
     buildCodecForObject<TalerCorebankApi.AccountMinimalData>()
+      .property("username", codecForString())
+      .property("name", codecForString())
+      .property("payto_uri", codecForPaytoString())
       .property("balance", codecForBalance())
       .property("debit_threshold", codecForAmountString())
-      .property("name", codecForString())
-      .property("username", codecForString())
       .property("is_public", codecForBoolean())
       .property("is_taler_exchange", codecForBoolean())
       .build("TalerCorebankApi.AccountMinimalData");
@@ -377,13 +380,6 @@ export const codecForChallengeContactData =
 export const codecForWithdrawalPublicInfo =
   (): Codec<TalerCorebankApi.WithdrawalPublicInfo> =>
     buildCodecForObject<TalerCorebankApi.WithdrawalPublicInfo>()
-      .property("username", codecForString())
-      .property("amount", codecForAmountString())
-      .property(
-        "selected_exchange_account",
-        codecOptional(codecForPaytoString()),
-      )
-      .property("selected_reserve_pub", codecOptional(codecForString()))
       .property(
         "status",
         codecForEither(
@@ -393,6 +389,13 @@ export const codecForWithdrawalPublicInfo =
           codecForConstString("confirmed"),
         ),
       )
+      .property("amount", codecForAmountString())
+      .property("username", codecForString())
+      .property("selected_reserve_pub", codecOptional(codecForString()))
+      .property(
+        "selected_exchange_account",
+        codecOptional(codecForPaytoString()),
+      )
       .build("TalerCorebankApi.WithdrawalPublicInfo");
 
 export const codecForBankAccountTransactionsResponse =
@@ -469,15 +472,6 @@ export const codecForCashouts = (): 
Codec<TalerCorebankApi.Cashouts> =>
 export const codecForCashoutInfo = (): Codec<TalerCorebankApi.CashoutInfo> =>
   buildCodecForObject<TalerCorebankApi.CashoutInfo>()
     .property("cashout_id", codecForNumber())
-    .property(
-      "status",
-      codecOptional(
-        codecForEither(
-          codecForConstString("pending"),
-          codecForConstString("aborted"),
-          codecForConstString("confirmed"),
-        )),
-    )
     .build("TalerCorebankApi.CashoutInfo");
 
 export const codecForGlobalCashouts =
@@ -491,41 +485,15 @@ export const codecForGlobalCashoutInfo =
     buildCodecForObject<TalerCorebankApi.GlobalCashoutInfo>()
       .property("cashout_id", codecForNumber())
       .property("username", codecForString())
-      .property(
-        "status",
-        codecOptional(
-          codecForEither(
-            codecForConstString("pending"),
-            codecForConstString("aborted"),
-            codecForConstString("confirmed"),
-          )),
-      )
       .build("TalerCorebankApi.GlobalCashoutInfo");
 
 export const codecForCashoutStatusResponse =
   (): Codec<TalerCorebankApi.CashoutStatusResponse> =>
     buildCodecForObject<TalerCorebankApi.CashoutStatusResponse>()
-      .property("amount_credit", codecForAmountString())
       .property("amount_debit", codecForAmountString())
-      .property("creation_time", codecForTimestamp)
-      .property(
-        "tan_channel",
-        codecOptional(codecForEither(
-          codecForConstString(TalerCorebankApi.TanChannel.SMS),
-          codecForConstString(TalerCorebankApi.TanChannel.EMAIL),
-        )),
-      )
+      .property("amount_credit", codecForAmountString())
       .property("subject", codecForString())
-      .property("confirmation_time", codecOptional(codecForTimestamp))
-      .property(
-        "status",
-        codecOptional(codecForEither(
-          codecForConstString("pending"),
-          codecForConstString("aborted"),
-          codecForConstString("confirmed"),
-        )),
-      )
-      .property("tan_info", codecOptional(codecForString()))
+      .property("creation_time", codecForTimestamp)
       .build("TalerCorebankApi.CashoutStatusResponse");
 
 export const codecForConversionRatesResponse =
@@ -607,7 +575,6 @@ export const codecForBankWithdrawalOperationPostResponse =
       .property(
         "status",
         codecForEither(
-          codecForConstString("pending"),
           codecForConstString("selected"),
           codecForConstString("aborted"),
           codecForConstString("confirmed"),
@@ -872,7 +839,7 @@ export const codecForConversionBankConfig =
       .property("fiat_currency", codecForString())
       .property("fiat_currency_specification", 
codecForCurrencySpecificiation())
 
-      .property("conversion_rate", codecOptional(codecForConversionInfo()))
+      .property("conversion_rate", (codecForConversionInfo()))
       .build("ConversionBankConfig.IntegrationConfig");
 
 // export const codecFor =
@@ -1177,7 +1144,7 @@ export namespace TalerBankConversionApi {
 
     // Extra conversion rate information.
     // Only present if server opts in to report the static conversion rate.
-    conversion_rate?: ConversionInfo;
+    conversion_rate: ConversionInfo;
   }
 
   export interface CashinConversionResponse {
@@ -1564,6 +1531,9 @@ export namespace TalerCorebankApi {
     // Legal name of the account owner.
     name: string;
 
+    // Internal payto URI of this bank account.
+    payto_uri: PaytoString;
+
     // current balance of the account
     balance: Balance;
 
@@ -1638,14 +1608,6 @@ export namespace TalerCorebankApi {
     // otherwise the request will fail.
     amount_credit: AmountString;
 
-    // Which channel the TAN should be sent to.  If
-    // this field is missing, it defaults to SMS.
-    // The default choice prefers to change the communication
-    // channel respect to the one used to issue this request.
-    /**
-     * @deprecated since 4, use 2fa
-     */
-    tan_channel?: TanChannel;
   }
 
   export interface CashoutResponse {
@@ -1680,10 +1642,6 @@ export namespace TalerCorebankApi {
   export interface GlobalCashoutInfo {
     cashout_id: number;
     username: string;
-    /**
-     * @deprecated since 4, use new 2fa
-     */
-    status?: "pending" | "aborted" | "confirmed";
   }
 
   export interface CashoutStatusResponse {
@@ -1698,38 +1656,8 @@ export namespace TalerCorebankApi {
     // Transaction subject.
     subject: string;
 
-    // Fiat bank account that will receive the cashed out amount.
-    // Specified as a payto URI.
-    // credit_payto_uri: PaytoString;
-
     // Time when the cashout was created.
     creation_time: Timestamp;
-
-    /**
-     * @deprecated since 4, use new 2fa
-     */
-    status?: "pending" | "aborted" | "confirmed";
-
-    // Time when the cashout was confirmed via its TAN.
-    // Missing when the operation wasn't confirmed yet.
-    /**
-     * @deprecated since 4, use new 2fa
-     */
-    confirmation_time?: Timestamp;
-
-    // Channel of the last successful transmission of the TAN challenge.
-    // Missing when all transmissions failed.
-    /**
-     * @deprecated since 4, use new 2fa
-     */
-    tan_channel?: TanChannel;
-
-    // Info of the last successful transmission of the TAN challenge.
-    // Missing when all transmissions failed.
-    /**
-     * @deprecated since 4, use new 2fa
-     */
-    tan_info?: string;
   }
 
   export interface ConversionRatesResponse {
diff --git a/packages/taler-util/src/http-client/utils.ts 
b/packages/taler-util/src/http-client/utils.ts
index ab6f809ef..e4b874c2f 100644
--- a/packages/taler-util/src/http-client/utils.ts
+++ b/packages/taler-util/src/http-client/utils.ts
@@ -1,6 +1,6 @@
 import { base64FromArrayBuffer } from "../base64.js";
 import { stringToBytes } from "../taler-crypto.js";
-import { AccessToken, PaginationParams } from "./types.js";
+import { AccessToken, LongPollParams, PaginationParams } from "./types.js";
 
 /**
  * Helper function to generate the "Authorization" HTTP header.
@@ -25,9 +25,6 @@ export function makeBearerTokenAuthHeader(token: 
AccessToken): string {
  */
 export function addPaginationParams(url: URL, pagination?: PaginationParams) {
   if (!pagination) return;
-  if (pagination.timoutMs) {
-    url.searchParams.set("long_poll_ms", String(pagination.timoutMs))
-  }
   if (pagination.offset) {
     url.searchParams.set("start", pagination.offset)
   }
@@ -36,3 +33,10 @@ export function addPaginationParams(url: URL, pagination?: 
PaginationParams) {
   //always send delta
   url.searchParams.set("delta", String(order * limit))
 }
+
+export function addLongPollingParam(url: URL, param?: LongPollParams) {
+  if (!param) return;
+  if (param.timeoutMs) {
+    url.searchParams.set("long_poll_ms", String(param.timeoutMs))
+  }
+}
diff --git a/packages/taler-util/src/operation.ts 
b/packages/taler-util/src/operation.ts
index fd31fce39..6656a20f2 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -61,10 +61,6 @@ export async function opKnownTalerFailure<T extends 
TalerErrorCode>(s: T, resp:
   const detail = await readTalerErrorResponse(resp)
   return { type: "fail", case: s, detail }
 }
-export async function opKnownFailure<T extends string>(s: T, resp: 
HttpResponse): Promise<OperationFail<T>> {
-  const detail = await readTalerErrorResponse(resp)
-  return { type: "fail", case: s, detail }
-}
 
 export function opUnknownFailure(resp: HttpResponse, text: string): never {
   throw TalerError.fromDetail(
diff --git a/packages/web-util/src/context/api.ts 
b/packages/web-util/src/context/api.ts
index b4a82065b..7923532b6 100644
--- a/packages/web-util/src/context/api.ts
+++ b/packages/web-util/src/context/api.ts
@@ -32,7 +32,7 @@ interface Type {
   bankRevenue: TalerRevenueHttpClient,
 }
 
-const Context = createContext<Type>({request: defaultRequestHandler} as any);
+const Context = createContext<Type>({ request: defaultRequestHandler } as any);
 
 export const useApiContext = (): Type => useContext(Context);
 export const ApiContextProvider = ({

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