gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: refactored terms of service t


From: gnunet
Subject: [taler-wallet-core] branch master updated: refactored terms of service to remove duplicated code prettfied some sources
Date: Fri, 14 Oct 2022 16:44:08 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new da9ec5eb1 refactored terms of service to remove duplicated code 
prettfied some sources
da9ec5eb1 is described below

commit da9ec5eb16298d8ca5690800eca1c15f5a6cfaa5
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Oct 14 11:40:38 2022 -0300

    refactored terms of service to remove duplicated code
    prettfied some sources
---
 .../src/components/CheckboxOutlined.tsx            |   4 +-
 .../src/cta/InvoiceCreate/index.ts                 |  10 +-
 .../src/cta/InvoiceCreate/state.ts                 |  23 +--
 .../src/cta/InvoiceCreate/stories.tsx              |   4 +-
 .../src/cta/{Tip => TermsOfService}/index.ts       |  72 ++++---
 .../src/cta/TermsOfService/state.ts                | 136 +++++++++++++
 .../{InvoiceCreate => TermsOfService}/stories.tsx  |  29 +--
 .../stories.tsx => TermsOfService/test.ts}         |  34 +---
 .../index.ts => cta/TermsOfService/utils.ts}       | 111 +---------
 .../src/cta/TermsOfService/views.tsx               | 224 +++++++++++++++++++++
 .../src/cta/TermsOfServiceSection.stories.tsx      | 187 -----------------
 .../src/cta/TermsOfServiceSection.tsx              | 196 ------------------
 .../taler-wallet-webextension/src/cta/Tip/index.ts |   3 +-
 .../src/cta/Withdraw/index.ts                      |  20 +-
 .../src/cta/Withdraw/state.ts                      | 191 +++++++++---------
 .../src/cta/Withdraw/stories.tsx                   |  82 ++++----
 .../src/cta/Withdraw/test.ts                       |  97 ++++-----
 .../src/cta/Withdraw/views.tsx                     |  79 ++++----
 .../src/cta/index.stories.ts                       |   2 +-
 .../src/hooks/useSelectedExchange.ts               |  92 +++++----
 .../taler-wallet-webextension/src/test-utils.ts    |   6 +-
 .../taler-wallet-webextension/src/utils/index.ts   | 133 +-----------
 .../src/wallet/AddAccount/index.ts                 |   6 +-
 .../src/wallet/AddAccount/state.ts                 |  63 +++---
 .../src/wallet/DepositPage/index.ts                |  18 +-
 .../src/wallet/DepositPage/state.ts                |  76 ++++---
 .../src/wallet/DepositPage/test.ts                 | 133 ++++++------
 .../src/wallet/ExchangeAddConfirm.stories.tsx      |  35 +---
 .../src/wallet/ExchangeAddConfirm.tsx              | 126 ++----------
 .../src/wallet/ExchangeSelection/index.ts          |  13 +-
 .../src/wallet/ExchangeSelection/state.ts          |  10 +-
 .../src/wallet/ExchangeSelection/views.tsx         |  36 ++--
 .../src/wallet/Settings.tsx                        |   2 +-
 packages/taler-wallet-webextension/src/wxApi.ts    |  45 +++--
 34 files changed, 989 insertions(+), 1309 deletions(-)

diff --git 
a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx 
b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
index 133c06339..79712c2f4 100644
--- a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
+++ b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
@@ -18,8 +18,8 @@ import { Outlined, StyledCheckboxLabel } from 
"./styled/index.js";
 import { h, VNode } from "preact";
 
 interface Props {
-  enabled: boolean;
-  onToggle: () => Promise<void>;
+  enabled?: boolean;
+  onToggle?: () => Promise<void>;
   label: VNode;
   name: string;
 }
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
index 61f286d1f..ff04a8247 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
@@ -17,9 +17,7 @@
 import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
-import {
-  State as SelectExchangeState
-} from "../../hooks/useSelectedExchange.js";
+import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
@@ -34,12 +32,12 @@ export interface Props {
   onSuccess: (tx: string) => Promise<void>;
 }
 
-export type State = State.Loading
+export type State =
+  | State.Loading
   | State.LoadingUriError
   | State.Ready
   | SelectExchangeState.Selecting
-  | SelectExchangeState.NoExchange
-  ;
+  | SelectExchangeState.NoExchange;
 
 export namespace State {
   export interface Loading {
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
index 4f75e982d..205a664e0 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
@@ -23,7 +23,7 @@ import { useSelectedExchange } from 
"../../hooks/useSelectedExchange.js";
 import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
-type RecursiveState<S extends object> = S | (() => RecursiveState<S>)
+type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
 
 export function useComponentState(
   { amount: amountStr, onClose, onSuccess }: Props,
@@ -46,7 +46,7 @@ export function useComponentState(
     };
   }
 
-  const exchangeList = hook.response.exchanges
+  const exchangeList = hook.response.exchanges;
 
   return () => {
     const [subject, setSubject] = useState("");
@@ -55,14 +55,17 @@ export function useComponentState(
       TalerErrorDetail | undefined
     >(undefined);
 
+    const selectedExchange = useSelectedExchange({
+      currency: amount.currency,
+      defaultExchange: undefined,
+      list: exchangeList,
+    });
 
-    const selectedExchange = useSelectedExchange({ currency: amount.currency, 
defaultExchange: undefined, list: exchangeList })
-
-    if (selectedExchange.status !== 'ready') {
-      return selectedExchange
+    if (selectedExchange.status !== "ready") {
+      return selectedExchange;
     }
 
-    const exchange = selectedExchange.selected
+    const exchange = selectedExchange.selected;
 
     async function accept(): Promise<void> {
       try {
@@ -105,9 +108,5 @@ export function useComponentState(
       error: undefined,
       operationError,
     };
-  }
-
-
-
-
+  };
 }
diff --git 
a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
index 306d1b199..77885b0c1 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
@@ -38,9 +38,7 @@ export const Ready = createExample(ReadyView, {
     value: 1,
     fraction: 0,
   },
-  doSelectExchange: {
-
-  },
+  doSelectExchange: {},
   exchangeUrl: "https://exchange.taler.ar";,
   subject: {
     value: "some subject",
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/index.ts
similarity index 53%
copy from packages/taler-wallet-webextension/src/cta/Tip/index.ts
copy to packages/taler-wallet-webextension/src/cta/TermsOfService/index.ts
index 157cf7d4e..9485f9d0a 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/index.ts
@@ -14,34 +14,35 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { AmountJson } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
-import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
+import { ToggleHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
-import { Props as TermsOfServiceSectionProps } from 
"../TermsOfServiceSection.js";
 import { useComponentState } from "./state.js";
+import { TermsState } from "./utils.js";
 import {
-  AcceptedView,
-  IgnoredView,
+  ErrorAcceptingView,
   LoadingUriView,
-  ReadyView,
+  ShowButtonsAcceptedTosView,
+  ShowButtonsNonAcceptedTosView,
+  ShowTosContentView,
 } from "./views.js";
 
 export interface Props {
-  talerTipUri?: string;
-  onCancel: () => Promise<void>;
-  onSuccess: (tx: string) => Promise<void>;
+  exchangeUrl: string;
+  onChange: (v: boolean) => void;
+  readOnly?: boolean;
 }
 
 export type State =
   | State.Loading
   | State.LoadingUriError
-  | State.Ignored
-  | State.Accepted
-  | State.Ready
-  | State.Ignored;
+  | State.ErrorAccepting
+  | State.ShowContent
+  | State.ShowButtonsAccepted
+  | State.ShowButtonsNotAccepted
+  | State.ShowContent;
 
 export namespace State {
   export interface Loading {
@@ -50,41 +51,46 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
+    status: "loading-error";
+    error: HookError;
+  }
+
+  export interface ErrorAccepting {
+    status: "error-accepting";
     error: HookError;
   }
 
   export interface BaseInfo {
-    merchantBaseUrl: string;
-    amount: AmountJson;
-    exchangeBaseUrl: string;
     error: undefined;
-    cancel: ButtonHandler;
+    termsAccepted: ToggleHandler;
+    showingTermsOfService: ToggleHandler;
+    terms: TermsState;
   }
-
-  export interface Ignored extends BaseInfo {
-    status: "ignored";
+  export interface ShowContent extends BaseInfo {
+    status: "show-content";
+    error: undefined;
   }
-
-  export interface Accepted extends BaseInfo {
-    status: "accepted";
+  export interface ShowButtonsAccepted extends BaseInfo {
+    status: "show-buttons-accepted";
+    error: undefined;
   }
-  export interface Ready extends BaseInfo {
-    status: "ready";
-    accept: ButtonHandler;
+  export interface ShowButtonsNotAccepted extends BaseInfo {
+    status: "show-buttons-not-accepted";
+    error: undefined;
   }
 }
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
-  accepted: AcceptedView,
-  ignored: IgnoredView,
-  ready: ReadyView,
+  "loading-error": LoadingUriView,
+  "show-content": ShowTosContentView,
+  "show-buttons-accepted": ShowButtonsAcceptedTosView,
+  "show-buttons-not-accepted": ShowButtonsNonAcceptedTosView,
+  "error-accepting": ErrorAcceptingView,
 };
 
-export const TipPage = compose(
-  "Tip",
+export const TermsOfService = compose(
+  "TermsOfService",
   (p: Props) => useComponentState(p, wxApi),
   viewMapping,
 );
diff --git a/packages/taler-wallet-webextension/src/cta/TermsOfService/state.ts 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/state.ts
new file mode 100644
index 000000000..4e89bc243
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/state.ts
@@ -0,0 +1,136 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import { useState } from "preact/hooks";
+import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
+import * as wxApi from "../../wxApi.js";
+import { Props, State } from "./index.js";
+import { buildTermsOfServiceState } from "./utils.js";
+
+export function useComponentState(
+  { exchangeUrl, readOnly, onChange }: Props,
+  api: typeof wxApi,
+): State {
+  const [showContent, setShowContent] = useState<boolean>(false);
+  // const [accepted, setAccepted] = useState<boolean>(false);
+  const [errorAccepting, setErrorAccepting] = useState<Error | undefined>(
+    undefined,
+  );
+
+  /**
+   * For the exchange selected, bring the status of the terms of service
+   */
+  const terms = useAsyncAsHook(async () => {
+    const exchangeTos = await api.getExchangeTos(exchangeUrl, ["text/xml"]);
+
+    const state = buildTermsOfServiceState(exchangeTos);
+
+    return { state };
+  }, []);
+
+  if (!terms) {
+    return {
+      status: "loading",
+      error: undefined,
+    };
+  }
+  if (terms.hasError) {
+    return {
+      status: "loading-error",
+      error: terms,
+    };
+  }
+
+  if (errorAccepting) {
+    return {
+      status: "error-accepting",
+      error: {
+        hasError: true,
+        operational: false,
+        message: errorAccepting.message,
+      },
+    };
+  }
+
+  const { state } = terms.response;
+
+  async function onUpdate(accepted: boolean): Promise<void> {
+    if (!state) return;
+
+    try {
+      if (accepted) {
+        await api.setExchangeTosAccepted(exchangeUrl, state.version);
+      } else {
+        // mark as not accepted
+        await api.setExchangeTosAccepted(exchangeUrl, undefined);
+      }
+      // setAccepted(accepted);
+      onChange(accepted); //external update
+    } catch (e) {
+      if (e instanceof Error) {
+        //FIXME: uncomment this and display error
+        // setErrorAccepting(e.message);
+        setErrorAccepting(e);
+      }
+    }
+  }
+
+  const accepted = state.status === "accepted";
+
+  const base: State.BaseInfo = {
+    error: undefined,
+    showingTermsOfService: {
+      value: showContent,
+      button: {
+        onClick: readOnly
+          ? undefined
+          : async () => {
+              setShowContent(!showContent);
+            },
+      },
+    },
+    terms: state,
+    termsAccepted: {
+      value: accepted,
+      button: {
+        onClick: async () => {
+          const newValue = !accepted; //toggle
+          onUpdate(newValue);
+          setShowContent(false);
+        },
+      },
+    },
+  };
+
+  if (showContent) {
+    return {
+      status: "show-content",
+      ...base,
+    };
+  }
+  //showing buttons
+  if (accepted) {
+    return {
+      status: "show-buttons-accepted",
+      ...base,
+    };
+  } else {
+    return {
+      status: "show-buttons-not-accepted",
+      ...base,
+    };
+  }
+}
diff --git 
a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/stories.tsx
similarity index 63%
copy from packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
copy to packages/taler-wallet-webextension/src/cta/TermsOfService/stories.tsx
index 306d1b199..2479274cb 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/stories.tsx
@@ -20,33 +20,10 @@
  */
 
 import { createExample } from "../../test-utils.js";
-import { ReadyView } from "./views.js";
+// import { ReadyView } from "./views.js";
 
 export default {
-  title: "wallet/invoice create",
+  title: "TermsOfService",
 };
 
-export const Ready = createExample(ReadyView, {
-  chosenAmount: {
-    currency: "ARS",
-    value: 1,
-    fraction: 0,
-  },
-  cancel: {},
-  toBeReceived: {
-    currency: "ARS",
-    value: 1,
-    fraction: 0,
-  },
-  doSelectExchange: {
-
-  },
-  exchangeUrl: "https://exchange.taler.ar";,
-  subject: {
-    value: "some subject",
-    onInput: async () => {
-      null;
-    },
-  },
-  create: {},
-});
+// export const Ready = createExample(ReadyView, {});
diff --git 
a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/test.ts
similarity index 58%
copy from packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
copy to packages/taler-wallet-webextension/src/cta/TermsOfService/test.ts
index 306d1b199..eae4d4ca2 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/test.ts
@@ -19,34 +19,10 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { createExample } from "../../test-utils.js";
-import { ReadyView } from "./views.js";
+import { expect } from "chai";
 
-export default {
-  title: "wallet/invoice create",
-};
-
-export const Ready = createExample(ReadyView, {
-  chosenAmount: {
-    currency: "ARS",
-    value: 1,
-    fraction: 0,
-  },
-  cancel: {},
-  toBeReceived: {
-    currency: "ARS",
-    value: 1,
-    fraction: 0,
-  },
-  doSelectExchange: {
-
-  },
-  exchangeUrl: "https://exchange.taler.ar";,
-  subject: {
-    value: "some subject",
-    onInput: async () => {
-      null;
-    },
-  },
-  create: {},
+describe("test description", () => {
+  it("should assert", () => {
+    expect([]).deep.equals([]);
+  });
 });
diff --git a/packages/taler-wallet-webextension/src/utils/index.ts 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/utils.ts
similarity index 53%
copy from packages/taler-wallet-webextension/src/utils/index.ts
copy to packages/taler-wallet-webextension/src/cta/TermsOfService/utils.ts
index 3535910cf..cee6557f7 100644
--- a/packages/taler-wallet-webextension/src/utils/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/utils.ts
@@ -14,69 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import {
-  AmountJson,
-  Amounts,
-  GetExchangeTosResult,
-} from "@gnu-taler/taler-util";
-import { VNode, createElement } from "preact";
-
-function getJsonIfOk(r: Response): Promise<any> {
-  if (r.ok) {
-    return r.json();
-  }
-
-  if (r.status >= 400 && r.status < 500) {
-    throw new Error(`URL may not be right: (${r.status}) ${r.statusText}`);
-  }
-
-  throw new Error(
-    `Try another server: (${r.status}) ${r.statusText || "internal server 
error"
-    }`,
-  );
-}
-
-export async function queryToSlashConfig<T>(url: string): Promise<T> {
-  return fetch(new URL("config", url).href)
-    .catch(() => {
-      throw new Error(`Network error`);
-    })
-    .then(getJsonIfOk);
-}
-
-function timeout<T>(ms: number, promise: Promise<T>): Promise<T> {
-  return new Promise((resolve, reject) => {
-    const timer = setTimeout(() => {
-      reject(
-        new Error(
-          `Timeout: the query took longer than ${Math.floor(ms / 1000)} secs`,
-        ),
-      );
-    }, ms);
-
-    promise
-      .then((value) => {
-        clearTimeout(timer);
-        resolve(value);
-      })
-      .catch((reason) => {
-        clearTimeout(timer);
-        reject(reason);
-      });
-  });
-}
-
-export async function queryToSlashKeys<T>(url: string): Promise<T> {
-  const endpoint = new URL("keys", url);
-
-  const query = fetch(endpoint.href)
-    .catch(() => {
-      throw new Error(`Network error`);
-    })
-    .then(getJsonIfOk);
-
-  return timeout(3000, query);
-}
+import { GetExchangeTosResult } from "@gnu-taler/taler-util";
 
 export function buildTermsOfServiceState(
   tos: GetExchangeTosResult,
@@ -102,10 +40,10 @@ export function buildTermsOfServiceStatus(
   return !content
     ? "notfound"
     : !acceptedVersion
-      ? "new"
-      : acceptedVersion !== currentVersion
-        ? "changed"
-        : "accepted";
+    ? "new"
+    : acceptedVersion !== currentVersion
+    ? "changed"
+    : "accepted";
 }
 
 function parseTermsOfServiceContent(
@@ -190,42 +128,3 @@ export interface TermsDocumentPdf {
   type: "pdf";
   location: URL;
 }
-
-export type StateFunc<S> = (p: S) => VNode;
-
-export type StateViewMap<StateType extends { status: string }> = {
-  [S in StateType as S["status"]]: StateFunc<S>;
-};
-
-type RecursiveState<S extends object> = S | (() => RecursiveState<S>)
-
-export function compose<SType extends { status: string }, PType>(
-  name: string,
-  hook: (p: PType) => RecursiveState<SType>,
-  viewMap: StateViewMap<SType>,
-): (p: PType) => VNode {
-
-  function withHook(stateHook: () => RecursiveState<SType>): () => VNode {
-
-    function TheComponent(): VNode {
-      const state = stateHook();
-
-      if (typeof state === "function") {
-        const subComponent = withHook(state)
-        return createElement(subComponent, {});
-      }
-
-      const statusName = state.status as unknown as SType["status"];
-      const viewComponent = viewMap[statusName] as unknown as StateFunc<SType>;
-      return createElement(viewComponent, state);
-    }
-    TheComponent.name = `${name}`;
-
-    return TheComponent;
-  }
-
-  return (p: PType) => {
-    const h = withHook(() => hook(p))
-    return h()
-  };
-}
diff --git 
a/packages/taler-wallet-webextension/src/cta/TermsOfService/views.tsx 
b/packages/taler-wallet-webextension/src/cta/TermsOfService/views.tsx
new file mode 100644
index 000000000..ed6d7dee4
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/cta/TermsOfService/views.tsx
@@ -0,0 +1,224 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import { Fragment, h, VNode } from "preact";
+import { LoadingError } from "../../components/LoadingError.js";
+import { useTranslationContext } from "../../context/translation.js";
+import { TermsState } from "./utils.js";
+import { State } from "./index.js";
+import { CheckboxOutlined } from "../../components/CheckboxOutlined.js";
+import {
+  LinkSuccess,
+  TermsOfService,
+  WarningBox,
+  WarningText,
+} from "../../components/styled/index.js";
+import { ExchangeXmlTos } from "../../components/ExchangeToS.js";
+import { ToggleHandler } from "../../mui/handlers.js";
+import { Button } from "../../mui/Button.js";
+
+export function LoadingUriView({ error }: State.LoadingUriError): VNode {
+  const { i18n } = useTranslationContext();
+
+  return (
+    <LoadingError
+      title={<i18n.Translate>Could not load</i18n.Translate>}
+      error={error}
+    />
+  );
+}
+
+export function ErrorAcceptingView({ error }: State.ErrorAccepting): VNode {
+  const { i18n } = useTranslationContext();
+
+  return (
+    <LoadingError
+      title={<i18n.Translate>Could not load</i18n.Translate>}
+      error={error}
+    />
+  );
+}
+
+export function ShowButtonsAcceptedTosView({
+  termsAccepted,
+  showingTermsOfService,
+  terms,
+}: State.ShowButtonsAccepted): VNode {
+  const { i18n } = useTranslationContext();
+  const ableToReviewTermsOfService =
+    showingTermsOfService.button.onClick !== undefined;
+
+  return (
+    <Fragment>
+      {ableToReviewTermsOfService && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <LinkSuccess
+            upperCased
+            onClick={showingTermsOfService.button.onClick}
+          >
+            <i18n.Translate>Show terms of service</i18n.Translate>
+          </LinkSuccess>
+        </section>
+      )}
+      <section style={{ justifyContent: "space-around", display: "flex" }}>
+        <CheckboxOutlined
+          name="terms"
+          enabled={termsAccepted.value}
+          label={
+            <i18n.Translate>
+              I accept the exchange terms of service
+            </i18n.Translate>
+          }
+          onToggle={termsAccepted.button.onClick}
+        />
+      </section>
+    </Fragment>
+  );
+}
+
+export function ShowButtonsNonAcceptedTosView({
+  termsAccepted,
+  showingTermsOfService,
+  terms,
+}: State.ShowButtonsNotAccepted): VNode {
+  const { i18n } = useTranslationContext();
+  const ableToReviewTermsOfService =
+    showingTermsOfService.button.onClick !== undefined;
+
+  if (!ableToReviewTermsOfService) {
+    return (
+      <Fragment>
+        {terms.status === "notfound" && (
+          <section style={{ justifyContent: "space-around", display: "flex" }}>
+            <WarningText>
+              <i18n.Translate>
+                Exchange doesn&apos;t have terms of service
+              </i18n.Translate>
+            </WarningText>
+          </section>
+        )}
+      </Fragment>
+    );
+  }
+
+  return (
+    <Fragment>
+      {terms.status === "notfound" && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <WarningText>
+            <i18n.Translate>
+              Exchange doesn&apos;t have terms of service
+            </i18n.Translate>
+          </WarningText>
+        </section>
+      )}
+      {terms.status === "new" && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <Button
+            variant="contained"
+            color="success"
+            onClick={showingTermsOfService.button.onClick}
+          >
+            <i18n.Translate>Review exchange terms of service</i18n.Translate>
+          </Button>
+        </section>
+      )}
+      {terms.status === "changed" && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <Button
+            variant="contained"
+            color="success"
+            onClick={showingTermsOfService.button.onClick}
+          >
+            <i18n.Translate>
+              Review new version of terms of service
+            </i18n.Translate>
+          </Button>
+        </section>
+      )}
+    </Fragment>
+  );
+}
+
+export function ShowTosContentView({
+  termsAccepted,
+  showingTermsOfService,
+  terms,
+}: State.ShowContent): VNode {
+  const { i18n } = useTranslationContext();
+  const ableToReviewTermsOfService =
+    showingTermsOfService.button.onClick !== undefined;
+
+  return (
+    <Fragment>
+      {terms.status !== "notfound" && !terms.content && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <WarningBox>
+            <i18n.Translate>
+              The exchange reply with a empty terms of service
+            </i18n.Translate>
+          </WarningBox>
+        </section>
+      )}
+      {terms.content && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          {terms.content.type === "xml" && (
+            <TermsOfService>
+              <ExchangeXmlTos doc={terms.content.document} />
+            </TermsOfService>
+          )}
+          {terms.content.type === "plain" && (
+            <div style={{ textAlign: "left" }}>
+              <pre>{terms.content.content}</pre>
+            </div>
+          )}
+          {terms.content.type === "html" && (
+            <iframe src={terms.content.href.toString()} />
+          )}
+          {terms.content.type === "pdf" && (
+            <a href={terms.content.location.toString()} download="tos.pdf">
+              <i18n.Translate>Download Terms of Service</i18n.Translate>
+            </a>
+          )}
+        </section>
+      )}
+      {termsAccepted && ableToReviewTermsOfService && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <LinkSuccess
+            upperCased
+            onClick={showingTermsOfService.button.onClick}
+          >
+            <i18n.Translate>Hide terms of service</i18n.Translate>
+          </LinkSuccess>
+        </section>
+      )}
+      {terms.status !== "notfound" && (
+        <section style={{ justifyContent: "space-around", display: "flex" }}>
+          <CheckboxOutlined
+            name="terms"
+            enabled={termsAccepted.value}
+            label={
+              <i18n.Translate>
+                I accept the exchange terms of service
+              </i18n.Translate>
+            }
+            onToggle={termsAccepted.button.onClick}
+          />
+        </section>
+      )}
+    </Fragment>
+  );
+}
diff --git 
a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.stories.tsx 
b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.stories.tsx
deleted file mode 100644
index 383daac59..000000000
--- 
a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.stories.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { createExample } from "../test-utils.js";
-import { termsHtml, termsPdf, termsPlain, termsXml } from "./termsExample.js";
-import { TermsOfServiceSection as TestedComponent } from 
"./TermsOfServiceSection.js";
-
-function parseFromString(s: string): Document {
-  if (typeof window === "undefined") {
-    return {} as Document;
-  }
-  return new window.DOMParser().parseFromString(s, "text/xml");
-}
-
-export default {
-  title: "cta/terms of service",
-  component: TestedComponent,
-};
-
-export const ReviewingPLAIN = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "plain",
-      content: termsPlain,
-    },
-    status: "new",
-    version: "",
-  },
-  reviewing: true,
-});
-
-export const ReviewingHTML = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "html",
-      href: new URL(`data:text/html;base64,${toBase64(termsHtml)}`),
-    },
-    version: "",
-    status: "new",
-  },
-  reviewing: true,
-});
-
-function toBase64(str: string): string {
-  const encoded = encodeURIComponent(str).replace(
-    /%([0-9A-F]{2})/g,
-    function (match, p1) {
-      return String.fromCharCode(parseInt(p1, 16));
-    },
-  );
-  if (typeof btoa === "undefined") {
-    //nodejs
-    return Buffer.from(encoded).toString("base64");
-  } else {
-    //browser
-    return btoa(encoded);
-  }
-}
-
-export const ReviewingPDF = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "pdf",
-      location: new URL(`data:text/html;base64,${toBase64(termsPdf)}`),
-    },
-    status: "new",
-    version: "",
-  },
-  reviewing: true,
-});
-
-export const ReviewingXML = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    status: "new",
-    version: "",
-  },
-  reviewing: true,
-});
-
-export const NewAccepted = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    status: "new",
-    version: "",
-  },
-  reviewed: true,
-});
-
-export const ShowAgainXML = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    version: "",
-    status: "new",
-  },
-  reviewed: true,
-  reviewing: true,
-});
-
-export const ChangedButNotReviewable = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    version: "",
-    status: "changed",
-  },
-});
-
-export const ChangedAndAllowReview = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    version: "",
-    status: "changed",
-  },
-  onReview: () => null,
-});
-
-export const NewButNotReviewable = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    version: "",
-    status: "new",
-  },
-});
-
-export const NewAndAllowReview = createExample(TestedComponent, {
-  terms: {
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-    version: "",
-    status: "new",
-  },
-  onReview: () => null,
-});
-
-export const NotFound = createExample(TestedComponent, {
-  terms: {
-    content: undefined,
-    status: "notfound",
-    version: "",
-  },
-});
-
-export const AlreadyAccepted = createExample(TestedComponent, {
-  terms: {
-    status: "accepted",
-    content: undefined,
-    version: "",
-  },
-});
diff --git 
a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx 
b/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx
deleted file mode 100644
index b60c86021..000000000
--- a/packages/taler-wallet-webextension/src/cta/TermsOfServiceSection.tsx
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-import { Fragment, h, VNode } from "preact";
-import { CheckboxOutlined } from "../components/CheckboxOutlined.js";
-import { ExchangeXmlTos } from "../components/ExchangeToS.js";
-import {
-  LinkSuccess,
-  TermsOfService,
-  WarningBox,
-  WarningText,
-} from "../components/styled/index.js";
-import { useTranslationContext } from "../context/translation.js";
-import { Button } from "../mui/Button.js";
-import { TermsState } from "../utils/index.js";
-
-export interface Props {
-  reviewing: boolean;
-  reviewed: boolean;
-  terms: TermsState;
-  onReview?: (b: boolean) => void;
-  onAccept: (b: boolean) => void;
-}
-export function TermsOfServiceSection({
-  reviewed,
-  reviewing,
-  terms,
-  onAccept,
-  onReview,
-}: Props): VNode {
-  const { i18n } = useTranslationContext();
-  const ableToReviewTermsOfService = onReview !== undefined;
-  if (!reviewing) {
-    if (!reviewed) {
-      if (!ableToReviewTermsOfService) {
-        return (
-          <Fragment>
-            {terms.status === "notfound" && (
-              <section
-                style={{ justifyContent: "space-around", display: "flex" }}
-              >
-                <WarningText>
-                  <i18n.Translate>
-                    Exchange doesn&apos;t have terms of service
-                  </i18n.Translate>
-                </WarningText>
-              </section>
-            )}
-          </Fragment>
-        );
-      }
-      return (
-        <Fragment>
-          {terms.status === "notfound" && (
-            <section
-              style={{ justifyContent: "space-around", display: "flex" }}
-            >
-              <WarningText>
-                <i18n.Translate>
-                  Exchange doesn&apos;t have terms of service
-                </i18n.Translate>
-              </WarningText>
-            </section>
-          )}
-          {terms.status === "new" && (
-            <section
-              style={{ justifyContent: "space-around", display: "flex" }}
-            >
-              <Button
-                variant="contained"
-                color="success"
-                onClick={async () => onReview(true)}
-              >
-                <i18n.Translate>
-                  Review exchange terms of service
-                </i18n.Translate>
-              </Button>
-            </section>
-          )}
-          {terms.status === "changed" && (
-            <section
-              style={{ justifyContent: "space-around", display: "flex" }}
-            >
-              <Button
-                variant="contained"
-                color="success"
-                onClick={async () => onReview(true)}
-              >
-                <i18n.Translate>
-                  Review new version of terms of service
-                </i18n.Translate>
-              </Button>
-            </section>
-          )}
-        </Fragment>
-      );
-    }
-    return (
-      <Fragment>
-        {ableToReviewTermsOfService && (
-          <section style={{ justifyContent: "space-around", display: "flex" }}>
-            <LinkSuccess upperCased onClick={() => onReview(true)}>
-              <i18n.Translate>Show terms of service</i18n.Translate>
-            </LinkSuccess>
-          </section>
-        )}
-        <section style={{ justifyContent: "space-around", display: "flex" }}>
-          <CheckboxOutlined
-            name="terms"
-            enabled={reviewed}
-            label={
-              <i18n.Translate>
-                I accept the exchange terms of service
-              </i18n.Translate>
-            }
-            onToggle={async () => {
-              onAccept(!reviewed);
-              if (ableToReviewTermsOfService) onReview(false);
-            }}
-          />
-        </section>
-      </Fragment>
-    );
-  }
-  return (
-    <Fragment>
-      {terms.status !== "notfound" && !terms.content && (
-        <section style={{ justifyContent: "space-around", display: "flex" }}>
-          <WarningBox>
-            <i18n.Translate>
-              The exchange reply with a empty terms of service
-            </i18n.Translate>
-          </WarningBox>
-        </section>
-      )}
-      {terms.status !== "accepted" && terms.content && (
-        <section style={{ justifyContent: "space-around", display: "flex" }}>
-          {terms.content.type === "xml" && (
-            <TermsOfService>
-              <ExchangeXmlTos doc={terms.content.document} />
-            </TermsOfService>
-          )}
-          {terms.content.type === "plain" && (
-            <div style={{ textAlign: "left" }}>
-              <pre>{terms.content.content}</pre>
-            </div>
-          )}
-          {terms.content.type === "html" && (
-            <iframe src={terms.content.href.toString()} />
-          )}
-          {terms.content.type === "pdf" && (
-            <a href={terms.content.location.toString()} download="tos.pdf">
-              <i18n.Translate>Download Terms of Service</i18n.Translate>
-            </a>
-          )}
-        </section>
-      )}
-      {reviewed && ableToReviewTermsOfService && (
-        <section style={{ justifyContent: "space-around", display: "flex" }}>
-          <LinkSuccess upperCased onClick={() => onReview(false)}>
-            <i18n.Translate>Hide terms of service</i18n.Translate>
-          </LinkSuccess>
-        </section>
-      )}
-      {terms.status !== "notfound" && (
-        <section style={{ justifyContent: "space-around", display: "flex" }}>
-          <CheckboxOutlined
-            name="terms"
-            enabled={reviewed}
-            label={
-              <i18n.Translate>
-                I accept the exchange terms of service
-              </i18n.Translate>
-            }
-            onToggle={async () => {
-              onAccept(!reviewed);
-              if (ableToReviewTermsOfService) onReview(false);
-            }}
-          />
-        </section>
-      )}
-    </Fragment>
-  );
-}
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
index 157cf7d4e..03cbd2196 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
@@ -17,10 +17,9 @@
 import { AmountJson } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
-import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
+import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
-import { Props as TermsOfServiceSectionProps } from 
"../TermsOfServiceSection.js";
 import { useComponentState } from "./state.js";
 import {
   AcceptedView,
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index 9de9c693a..075b21dc3 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -14,27 +14,20 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { AmountJson } from "@gnu-taler/taler-util";
+import { AmountJson, ExchangeListItem } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
-import {
-  State as SelectExchangeState
-} from "../../hooks/useSelectedExchange.js";
+import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
-import { Props as TermsOfServiceSectionProps } from 
"../TermsOfServiceSection.js";
 import {
   useComponentStateFromParams,
-  useComponentStateFromURI
+  useComponentStateFromURI,
 } from "./state.js";
 
 import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
-import {
-  LoadingInfoView,
-  LoadingUriView,
-  SuccessView
-} from "./views.js";
+import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
 import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
 
 export interface PropsFromURI {
@@ -75,7 +68,7 @@ export namespace State {
     status: "success";
     error: undefined;
 
-    exchangeUrl: string;
+    currentExchange: ExchangeListItem;
 
     chosenAmount: AmountJson;
     withdrawalFee: AmountJson;
@@ -83,13 +76,12 @@ export namespace State {
 
     doWithdrawal: ButtonHandler;
     doSelectExchange: ButtonHandler;
-    tosProps?: TermsOfServiceSectionProps;
-    mustAcceptFirst: boolean;
 
     ageRestriction?: SelectFieldHandler;
 
     talerWithdrawUri?: string;
     cancel: () => Promise<void>;
+    onTosUpdate: () => void;
   };
 }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index 5b5c11182..c2b9e375f 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -15,17 +15,15 @@
  */
 
 /* eslint-disable react-hooks/rules-of-hooks */
-import { AmountJson, Amounts, ExchangeListItem, parsePaytoUri } from 
"@gnu-taler/taler-util";
+import { AmountJson, Amounts, ExchangeListItem } from "@gnu-taler/taler-util";
 import { TalerError } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
-import { Amount } from "../../components/Amount.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
-import { buildTermsOfServiceState } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
-import { PropsFromURI, PropsFromParams, State } from "./index.js";
+import { PropsFromParams, PropsFromURI, State } from "./index.js";
 
-type RecursiveState<S extends object> = S | (() => RecursiveState<S>)
+type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
 
 export function useComponentStateFromParams(
   { amount, cancel, onSuccess }: PropsFromParams,
@@ -46,18 +44,38 @@ export function useComponentStateFromParams(
   }
 
   const chosenAmount = uriInfoHook.response.amount;
-  const exchangeList = uriInfoHook.response.exchanges.exchanges
-
-  async function doManualWithdraw(exchange: string, ageRestricted: number | 
undefined): Promise<{ transactionId: string, confirmTransferUrl: string | 
undefined }> {
-    const res = await api.acceptManualWithdrawal(exchange, 
Amounts.stringify(chosenAmount), ageRestricted);
+  const exchangeList = uriInfoHook.response.exchanges.exchanges;
+
+  async function doManualWithdraw(
+    exchange: string,
+    ageRestricted: number | undefined,
+  ): Promise<{
+    transactionId: string;
+    confirmTransferUrl: string | undefined;
+  }> {
+    const res = await api.acceptManualWithdrawal(
+      exchange,
+      Amounts.stringify(chosenAmount),
+      ageRestricted,
+    );
     return {
       confirmTransferUrl: undefined,
-      transactionId: res.transactionId
+      transactionId: res.transactionId,
     };
   }
 
-  return () => exchangeSelectionState(doManualWithdraw, cancel, onSuccess, 
undefined, chosenAmount, exchangeList, undefined, api)
-
+  return () =>
+    exchangeSelectionState(
+      uriInfoHook.retry,
+      doManualWithdraw,
+      cancel,
+      onSuccess,
+      undefined,
+      chosenAmount,
+      exchangeList,
+      undefined,
+      api,
+    );
 }
 
 export function useComponentStateFromURI(
@@ -75,7 +93,12 @@ export function useComponentStateFromURI(
     });
     const exchanges = await api.listExchanges();
     const { amount, defaultExchangeBaseUrl } = uriInfo;
-    return { talerWithdrawUri, amount: Amounts.parseOrThrow(amount), 
thisExchange: defaultExchangeBaseUrl, exchanges };
+    return {
+      talerWithdrawUri,
+      amount: Amounts.parseOrThrow(amount),
+      thisExchange: defaultExchangeBaseUrl,
+      exchanges,
+    };
   });
 
   if (!uriInfoHook) return { status: "loading", error: undefined };
@@ -90,53 +113,75 @@ export function useComponentStateFromURI(
   const uri = uriInfoHook.response.talerWithdrawUri;
   const chosenAmount = uriInfoHook.response.amount;
   const defaultExchange = uriInfoHook.response.thisExchange;
-  const exchangeList = uriInfoHook.response.exchanges.exchanges
-
-  async function doManagedWithdraw(exchange: string, ageRestricted: number | 
undefined): Promise<{ transactionId: string, confirmTransferUrl: string | 
undefined }> {
-    const res = await api.acceptWithdrawal(uri, exchange, ageRestricted,);
+  const exchangeList = uriInfoHook.response.exchanges.exchanges;
+
+  async function doManagedWithdraw(
+    exchange: string,
+    ageRestricted: number | undefined,
+  ): Promise<{
+    transactionId: string;
+    confirmTransferUrl: string | undefined;
+  }> {
+    const res = await api.acceptWithdrawal(uri, exchange, ageRestricted);
     return {
       confirmTransferUrl: res.confirmTransferUrl,
-      transactionId: res.transactionId
+      transactionId: res.transactionId,
     };
   }
 
-  return () => exchangeSelectionState(doManagedWithdraw, cancel, onSuccess, 
uri, chosenAmount, exchangeList, defaultExchange, api)
-
+  return () =>
+    exchangeSelectionState(
+      uriInfoHook.retry,
+      doManagedWithdraw,
+      cancel,
+      onSuccess,
+      uri,
+      chosenAmount,
+      exchangeList,
+      defaultExchange,
+      api,
+    );
 }
 
-type ManualOrManagedWithdrawFunction = (exchange: string, ageRestricted: 
number | undefined) => Promise<{ transactionId: string, confirmTransferUrl: 
string | undefined }>
-
-function exchangeSelectionState(doWithdraw: ManualOrManagedWithdrawFunction, 
cancel: () => Promise<void>, onSuccess: (txid: string) => Promise<void>, 
talerWithdrawUri: string | undefined, chosenAmount: AmountJson, exchangeList: 
ExchangeListItem[], defaultExchange: string | undefined, api: typeof wxApi,): 
RecursiveState<State> {
-
-  const selectedExchange = useSelectedExchange({ currency: 
chosenAmount.currency, defaultExchange, list: exchangeList })
+type ManualOrManagedWithdrawFunction = (
+  exchange: string,
+  ageRestricted: number | undefined,
+) => Promise<{ transactionId: string; confirmTransferUrl: string | undefined 
}>;
+
+function exchangeSelectionState(
+  onTosUpdate: () => void,
+  doWithdraw: ManualOrManagedWithdrawFunction,
+  cancel: () => Promise<void>,
+  onSuccess: (txid: string) => Promise<void>,
+  talerWithdrawUri: string | undefined,
+  chosenAmount: AmountJson,
+  exchangeList: ExchangeListItem[],
+  defaultExchange: string | undefined,
+  api: typeof wxApi,
+): RecursiveState<State> {
+  const selectedExchange = useSelectedExchange({
+    currency: chosenAmount.currency,
+    defaultExchange,
+    list: exchangeList,
+  });
 
-  if (selectedExchange.status !== 'ready') {
-    return selectedExchange
+  if (selectedExchange.status !== "ready") {
+    return selectedExchange;
   }
 
   return () => {
-
     const [ageRestricted, setAgeRestricted] = useState(0);
-    const currentExchange = selectedExchange.selected
-    /**
-     * For the exchange selected, bring the status of the terms of service
-     */
-    const terms = useAsyncAsHook(async () => {
-      const exchangeTos = await 
api.getExchangeTos(currentExchange.exchangeBaseUrl, [
-        "text/xml",
-      ]);
-
-      const state = buildTermsOfServiceState(exchangeTos);
-
-      return { state };
-    }, []);
+    const currentExchange = selectedExchange.selected;
+    const tosNeedToBeAccepted =
+      !currentExchange.tos.acceptedVersion ||
+      currentExchange.tos.currentVersion !==
+        currentExchange.tos.acceptedVersion;
 
     /**
      * With the exchange and amount, ask the wallet the information
      * about the withdrawal
      */
     const amountHook = useAsyncAsHook(async () => {
-
       const info = await api.getExchangeWithdrawalInfo({
         exchangeBaseUrl: currentExchange.exchangeBaseUrl,
         amount: chosenAmount,
@@ -155,20 +200,18 @@ function exchangeSelectionState(doWithdraw: 
ManualOrManagedWithdrawFunction, can
       };
     }, []);
 
-    const [reviewing, setReviewing] = useState<boolean>(false);
-    const [reviewed, setReviewed] = useState<boolean>(false);
-
     const [withdrawError, setWithdrawError] = useState<TalerError | undefined>(
       undefined,
     );
     const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false);
 
-
     async function doWithdrawAndCheckError(): Promise<void> {
-
       try {
         setDoingWithdraw(true);
-        const res = await doWithdraw(currentExchange.exchangeBaseUrl, 
!ageRestricted ? undefined : ageRestricted)
+        const res = await doWithdraw(
+          currentExchange.exchangeBaseUrl,
+          !ageRestricted ? undefined : ageRestricted,
+        );
         if (res.confirmTransferUrl) {
           document.location.href = res.confirmTransferUrl;
         } else {
@@ -201,33 +244,6 @@ function exchangeSelectionState(doWithdraw: 
ManualOrManagedWithdrawFunction, can
     ).amount;
     const toBeReceived = amountHook.response.amount.effective;
 
-    const { state: termsState } = (!terms
-      ? undefined
-      : terms.hasError
-        ? undefined
-        : terms.response) || { state: undefined };
-
-    async function onAccept(accepted: boolean): Promise<void> {
-      if (!termsState) return;
-
-      try {
-        await api.setExchangeTosAccepted(
-          currentExchange.exchangeBaseUrl,
-          accepted ? termsState.version : undefined,
-        );
-        setReviewed(accepted);
-      } catch (e) {
-        if (e instanceof Error) {
-          //FIXME: uncomment this and display error
-          // setErrorAccepting(e.message);
-        }
-      }
-    }
-
-    const mustAcceptFirst =
-      termsState !== undefined &&
-      (termsState.status === "changed" || termsState.status === "new");
-
     const ageRestrictionOptions =
       amountHook.response.ageRestrictionOptions?.reduce(
         (p, c) => ({ ...p, [c]: `under ${c}` }),
@@ -242,17 +258,17 @@ function exchangeSelectionState(doWithdraw: 
ManualOrManagedWithdrawFunction, can
     //TODO: calculate based on exchange info
     const ageRestriction = ageRestrictionEnabled
       ? {
-        list: ageRestrictionOptions,
-        value: String(ageRestricted),
-        onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)),
-      }
+          list: ageRestrictionOptions,
+          value: String(ageRestricted),
+          onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)),
+        }
       : undefined;
 
     return {
       status: "success",
       error: undefined,
       doSelectExchange: selectedExchange.doSelect,
-      exchangeUrl: currentExchange.exchangeBaseUrl,
+      currentExchange,
       toBeReceived,
       withdrawalFee,
       chosenAmount,
@@ -260,22 +276,13 @@ function exchangeSelectionState(doWithdraw: 
ManualOrManagedWithdrawFunction, can
       ageRestriction,
       doWithdrawal: {
         onClick:
-          doingWithdraw || (mustAcceptFirst && !reviewed)
+          doingWithdraw || tosNeedToBeAccepted
             ? undefined
             : doWithdrawAndCheckError,
         error: withdrawError,
       },
-      tosProps: !termsState
-        ? undefined
-        : {
-          onAccept,
-          onReview: setReviewing,
-          reviewed: reviewed,
-          reviewing: reviewing,
-          terms: termsState,
-        },
-      mustAcceptFirst,
+      onTosUpdate,
       cancel,
     };
-  }
+  };
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
index a3daeb5e9..1c3eaaf34 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
@@ -19,8 +19,9 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
+import { ExchangeListItem } from "@gnu-taler/taler-util";
 import { createExample } from "../../test-utils.js";
-import { TermsState } from "../../utils/index.js";
+// import { TermsState } from "../../utils/index.js";
 import { SuccessView } from "./views.js";
 
 export default {
@@ -38,16 +39,16 @@ const nullHandler = {
   },
 };
 
-const normalTosState = {
-  terms: {
-    status: "accepted",
-    version: "",
-  } as TermsState,
-  onAccept: () => null,
-  onReview: () => null,
-  reviewed: false,
-  reviewing: false,
-};
+// const normalTosState = {
+//   terms: {
+//     status: "accepted",
+//     version: "",
+//   } as TermsState,
+//   onAccept: () => null,
+//   onReview: () => null,
+//   reviewed: false,
+//   reviewing: false,
+// };
 
 const ageRestrictionOptions: Record<string, string> = "6:12:18"
   .split(":")
@@ -69,15 +70,16 @@ export const TermsOfServiceNotYetLoaded = 
createExample(SuccessView, {
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 10000000,
     value: 1,
   },
-  doSelectExchange: {
-  },
+  doSelectExchange: {},
   toBeReceived: {
     currency: "USD",
     fraction: 0,
@@ -94,8 +96,10 @@ export const WithSomeFee = createExample(SuccessView, {
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 10000000,
@@ -106,9 +110,7 @@ export const WithSomeFee = createExample(SuccessView, {
     fraction: 0,
     value: 1,
   },
-  doSelectExchange: {
-  },
-  tosProps: normalTosState,
+  doSelectExchange: {},
 });
 
 export const WithoutFee = createExample(SuccessView, {
@@ -120,21 +122,21 @@ export const WithoutFee = createExample(SuccessView, {
     fraction: 0,
   },
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 0,
     value: 0,
   },
-  doSelectExchange: {
-  },
+  doSelectExchange: {},
   toBeReceived: {
     currency: "USD",
     fraction: 0,
     value: 2,
   },
-  tosProps: normalTosState,
 });
 
 export const EditExchangeUntouched = createExample(SuccessView, {
@@ -146,21 +148,21 @@ export const EditExchangeUntouched = 
createExample(SuccessView, {
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 0,
     value: 0,
   },
-  doSelectExchange: {
-  },
+  doSelectExchange: {},
   toBeReceived: {
     currency: "USD",
     fraction: 0,
     value: 2,
   },
-  tosProps: normalTosState,
 });
 
 export const EditExchangeModified = createExample(SuccessView, {
@@ -172,21 +174,21 @@ export const EditExchangeModified = 
createExample(SuccessView, {
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 0,
     value: 0,
   },
-  doSelectExchange: {
-  },
+  doSelectExchange: {},
   toBeReceived: {
     currency: "USD",
     fraction: 0,
     value: 2,
   },
-  tosProps: normalTosState,
 });
 
 export const WithAgeRestriction = createExample(SuccessView, {
@@ -198,11 +200,12 @@ export const WithAgeRestriction = 
createExample(SuccessView, {
     value: 2,
     fraction: 10000000,
   },
-  doSelectExchange: {
-  },
+  doSelectExchange: {},
   doWithdrawal: nullHandler,
-  exchangeUrl: "https://exchange.demo.taler.net";,
-  mustAcceptFirst: false,
+  currentExchange: {
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    tos: {},
+  } as Partial<ExchangeListItem> as any,
   withdrawalFee: {
     currency: "USD",
     fraction: 0,
@@ -213,5 +216,4 @@ export const WithAgeRestriction = 
createExample(SuccessView, {
     fraction: 0,
     value: 2,
   },
-  tosProps: normalTosState,
 });
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index 7ccf7f606..f3598b557 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -37,7 +37,8 @@ const exchanges: ExchangeFullDetails[] = [
     exchangeBaseUrl: "http://exchange.demo.taler.net";,
     paytoUris: [],
     tos: {
-      acceptedVersion: "",
+      acceptedVersion: "v1",
+      currentVersion: "v1",
     },
     auditors: [
       {
@@ -58,7 +59,7 @@ const exchanges: ExchangeFullDetails[] = [
       accounts: [],
       feesForType: {},
     },
-  },
+  } as Partial<ExchangeFullDetails> as ExchangeFullDetails,
 ];
 
 describe("Withdraw CTA states", () => {
@@ -161,17 +162,20 @@ describe("Withdraw CTA states", () => {
           },
           {
             listExchanges: async () => ({ exchanges }),
-            getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
-              amount: "ARS:2",
-              possibleExchanges: exchanges,
-              defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
-            }),
+            getWithdrawalDetailsForUri: async ({
+              talerWithdrawUri,
+            }: any): Promise<ExchangeWithdrawDetails> =>
+              ({
+                amount: "ARS:2",
+                possibleExchanges: exchanges,
+                defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
+              } as Partial<ExchangeWithdrawDetails> as 
ExchangeWithdrawDetails),
             getExchangeWithdrawalInfo:
               async (): Promise<ExchangeWithdrawDetails> =>
-              ({
-                withdrawalAmountRaw: "ARS:2",
-                withdrawalAmountEffective: "ARS:2",
-              } as any),
+                ({
+                  withdrawalAmountRaw: "ARS:2",
+                  withdrawalAmountEffective: "ARS:2",
+                } as any),
             getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
               contentType: "text",
               content: "just accept",
@@ -205,25 +209,39 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      // expect(state.exchange.isDirty).false;
-      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      // expect(state.exchange.list).deep.equal({
-      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      // });
-      // expect(state.showExchangeSelection).false;
-
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
       expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2"));
 
       expect(state.doWithdrawal.onClick).not.undefined;
-      expect(state.mustAcceptFirst).false;
     }
 
     await assertNoPendingUpdate();
   });
 
   it("should be accept the tos before withdraw", async () => {
+    const listExchangesResponse = {
+      exchanges: exchanges.map((e) => ({
+        ...e,
+        tos: {
+          ...e.tos,
+          acceptedVersion: undefined,
+        },
+      })) as ExchangeFullDetails[],
+    };
+
+    function updateAcceptedVersionToCurrentVersion(): void {
+      listExchangesResponse.exchanges = listExchangesResponse.exchanges.map(
+        (e) => ({
+          ...e,
+          tos: {
+            ...e.tos,
+            acceptedVersion: e.tos.currentVersion,
+          },
+        }),
+      );
+    }
+
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
         useComponentStateFromURI(
@@ -237,18 +255,19 @@ describe("Withdraw CTA states", () => {
             },
           },
           {
-            listExchanges: async () => ({ exchanges }),
-            getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
-              amount: "ARS:2",
-              possibleExchanges: exchanges,
-              defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
-            }),
+            listExchanges: async () => listExchangesResponse,
+            getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) =>
+              ({
+                amount: "ARS:2",
+                possibleExchanges: exchanges,
+                defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
+              } as Partial<ExchangeWithdrawDetails> as 
ExchangeWithdrawDetails),
             getExchangeWithdrawalInfo:
               async (): Promise<ExchangeWithdrawDetails> =>
-              ({
-                withdrawalAmountRaw: "ARS:2",
-                withdrawalAmountEffective: "ARS:2",
-              } as any),
+                ({
+                  withdrawalAmountRaw: "ARS:2",
+                  withdrawalAmountEffective: "ARS:2",
+                } as any),
             getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
               contentType: "text",
               content: "just accept",
@@ -283,22 +302,14 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      // expect(state.exchange.isDirty).false;
-      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      // expect(state.exchange.list).deep.equal({
-      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      // });
-      // expect(state.showExchangeSelection).false;
-
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
       expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2"));
 
       expect(state.doWithdrawal.onClick).undefined;
-      expect(state.mustAcceptFirst).true;
 
-      // accept TOS
-      state.tosProps?.onAccept(true);
+      updateAcceptedVersionToCurrentVersion();
+      state.onTosUpdate();
     }
 
     await waitNextUpdate();
@@ -308,19 +319,11 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      // expect(state.exchange.isDirty).false;
-      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      // expect(state.exchange.list).deep.equal({
-      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      // });
-      // expect(state.showExchangeSelection).false;
-
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
       expect(state.chosenAmount).deep.equal(Amounts.parseOrThrow("ARS:2"));
 
       expect(state.doWithdrawal.onClick).not.undefined;
-      expect(state.mustAcceptFirst).true;
     }
 
     await assertNoPendingUpdate();
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 1e8284739..44c7db83f 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -15,30 +15,28 @@
  */
 
 import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Amount } from "../../components/Amount.js";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
 import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
+import { QR } from "../../components/QR.js";
 import { SelectList } from "../../components/SelectList.js";
 import {
   Input,
   Link,
   LinkSuccess,
   SubTitle,
-  SuccessBox,
   SvgIcon,
   WalletAction,
 } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
+import editIcon from "../../svg/edit_24px.svg";
 import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
-import { TermsOfServiceSection } from "../TermsOfServiceSection.js";
+import { TermsOfService } from "../TermsOfService/index.js";
 import { State } from "./index.js";
-import editIcon from "../../svg/edit_24px.svg";
-import { Amount } from "../../components/Amount.js";
-import { QR } from "../../components/QR.js";
-import { useState } from "preact/hooks";
-import { ErrorMessage } from "../../components/ErrorMessage.js";
 
 export function LoadingUriView({ error }: State.LoadingUriError): VNode {
   const { i18n } = useTranslationContext();
@@ -66,6 +64,9 @@ export function LoadingInfoView({ error }: 
State.LoadingInfoError): VNode {
 
 export function SuccessView(state: State.Success): VNode {
   const { i18n } = useTranslationContext();
+  const currentTosVersionIsAccepted =
+    state.currentExchange.tos.acceptedVersion ===
+    state.currentExchange.tos.currentVersion;
   return (
     <WalletAction>
       <LogoHeader />
@@ -103,7 +104,9 @@ export function SuccessView(state: State.Success): VNode {
               </Button>
             </div>
           }
-          text={<ExchangeDetails exchange={state.exchangeUrl} />}
+          text={
+            <ExchangeDetails exchange={state.currentExchange.exchangeBaseUrl} 
/>
+          }
           kind="neutral"
           big
         />
@@ -130,43 +133,29 @@ export function SuccessView(state: State.Success): VNode {
           </Input>
         )}
       </section>
-      {state.tosProps && <TermsOfServiceSection {...state.tosProps} />}
-      {state.tosProps ? (
-        <Fragment>
-          <section>
-            {(state.tosProps.terms.status === "accepted" ||
-              (state.mustAcceptFirst && state.tosProps.reviewed)) && (
-              <Button
-                variant="contained"
-                color="success"
-                disabled={!state.doWithdrawal.onClick}
-                onClick={state.doWithdrawal.onClick}
-              >
-                <i18n.Translate>
-                  Withdraw &nbsp; <Amount value={state.toBeReceived} />
-                </i18n.Translate>
-              </Button>
-            )}
-            {state.tosProps.terms.status === "notfound" && (
-              <Button
-                variant="contained"
-                color="warning"
-                disabled={!state.doWithdrawal.onClick}
-                onClick={state.doWithdrawal.onClick}
-              >
-                <i18n.Translate>Withdraw anyway</i18n.Translate>
-              </Button>
-            )}
-          </section>
-          {state.talerWithdrawUri ? (
-            <WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
-          ) : undefined}
-        </Fragment>
-      ) : (
-        <section>
-          <i18n.Translate>Loading terms of service...</i18n.Translate>
-        </section>
-      )}
+
+      <section>
+        {currentTosVersionIsAccepted ? (
+          <Button
+            variant="contained"
+            color="success"
+            disabled={!state.doWithdrawal.onClick}
+            onClick={state.doWithdrawal.onClick}
+          >
+            <i18n.Translate>
+              Withdraw &nbsp; <Amount value={state.toBeReceived} />
+            </i18n.Translate>
+          </Button>
+        ) : (
+          <TermsOfService
+            exchangeUrl={state.currentExchange.exchangeBaseUrl}
+            onChange={state.onTosUpdate}
+          />
+        )}
+      </section>
+      {state.talerWithdrawUri ? (
+        <WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
+      ) : undefined}
       <section>
         <Link upperCased onClick={state.cancel}>
           <i18n.Translate>Cancel</i18n.Translate>
diff --git a/packages/taler-wallet-webextension/src/cta/index.stories.ts 
b/packages/taler-wallet-webextension/src/cta/index.stories.ts
index 2f0ef33fb..c54defccf 100644
--- a/packages/taler-wallet-webextension/src/cta/index.stories.ts
+++ b/packages/taler-wallet-webextension/src/cta/index.stories.ts
@@ -24,7 +24,7 @@ import * as a3 from "./Payment/stories.jsx";
 import * as a4 from "./Refund/stories.jsx";
 import * as a5 from "./Tip/stories.jsx";
 import * as a6 from "./Withdraw/stories.jsx";
-import * as a7 from "./TermsOfServiceSection.stories.js";
+import * as a7 from "./TermsOfService/stories.js";
 import * as a8 from "./InvoiceCreate/stories.js";
 import * as a9 from "./InvoicePay/stories.js";
 import * as a10 from "./TransferCreate/stories.js";
diff --git 
a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts 
b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
index 7219c30d2..c04dcce84 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
@@ -22,21 +22,21 @@ type State = State.Ready | State.NoExchange | 
State.Selecting;
 
 export namespace State {
   export interface NoExchange {
-    status: "no-exchange"
+    status: "no-exchange";
     error: undefined;
     currency: string | undefined;
   }
   export interface Ready {
-    status: "ready",
-    doSelect: ButtonHandler,
+    status: "ready";
+    doSelect: ButtonHandler;
     selected: ExchangeListItem;
   }
   export interface Selecting {
-    status: "selecting-exchange",
-    error: undefined,
+    status: "selecting-exchange";
+    error: undefined;
     onSelection: (url: string) => Promise<void>;
     onCancel: () => Promise<void>;
-    list: ExchangeListItem[],
+    list: ExchangeListItem[];
     currency: string;
     currentExchange: string;
   }
@@ -45,38 +45,42 @@ export namespace State {
 interface Props {
   currency: string;
   //there is a preference for the default at the initial state
-  defaultExchange?: string,
+  defaultExchange?: string;
   //list of exchanges
-  list: ExchangeListItem[],
+  list: ExchangeListItem[];
 }
 
-
-
-export function useSelectedExchange({ currency, defaultExchange, list }: 
Props): State {
+export function useSelectedExchange({
+  currency,
+  defaultExchange,
+  list,
+}: Props): State {
   const [isSelecting, setIsSelecting] = useState(false);
-  const [selectedExchange, setSelectedExchange] = useState<string | 
undefined>(undefined);
+  const [selectedExchange, setSelectedExchange] = useState<string | undefined>(
+    undefined,
+  );
 
   if (!list.length) {
     return {
       status: "no-exchange",
       error: undefined,
       currency: undefined,
-    }
+    };
   }
 
-  const listCurrency = list.filter((e) => e.currency === currency)
+  const listCurrency = list.filter((e) => e.currency === currency);
   if (!listCurrency.length) {
     // there should be at least one exchange for this currency
     return {
       status: "no-exchange",
       error: undefined,
       currency,
-    }
+    };
   }
 
-
   if (isSelecting) {
-    const currentExchange = selectedExchange ?? defaultExchange ?? 
listCurrency[0].exchangeBaseUrl;
+    const currentExchange =
+      selectedExchange ?? defaultExchange ?? listCurrency[0].exchangeBaseUrl;
     return {
       status: "selecting-exchange",
       error: undefined,
@@ -85,44 +89,46 @@ export function useSelectedExchange({ currency, 
defaultExchange, list }: Props):
       currentExchange: currentExchange,
       onSelection: async (exchangeBaseUrl: string) => {
         setIsSelecting(false);
-        setSelectedExchange(exchangeBaseUrl)
+        setSelectedExchange(exchangeBaseUrl);
       },
       onCancel: async () => {
         setIsSelecting(false);
-      }
-    }
+      },
+    };
   }
 
   {
-    const found = !selectedExchange ? undefined : list.find(
-      (e) => e.exchangeBaseUrl === selectedExchange,
-    )
-    if (found) return {
-      status: "ready",
-      doSelect: {
-        onClick: async () => setIsSelecting(true)
-      },
-      selected: found
-    };
+    const found = !selectedExchange
+      ? undefined
+      : list.find((e) => e.exchangeBaseUrl === selectedExchange);
+    if (found)
+      return {
+        status: "ready",
+        doSelect: {
+          onClick: async () => setIsSelecting(true),
+        },
+        selected: found,
+      };
   }
   {
-    const found = !defaultExchange ? undefined : list.find(
-      (e) => e.exchangeBaseUrl === defaultExchange,
-    )
-    if (found) return {
-      status: "ready",
-      doSelect: {
-        onClick: async () => setIsSelecting(true)
-      },
-      selected: found
-    };
+    const found = !defaultExchange
+      ? undefined
+      : list.find((e) => e.exchangeBaseUrl === defaultExchange);
+    if (found)
+      return {
+        status: "ready",
+        doSelect: {
+          onClick: async () => setIsSelecting(true),
+        },
+        selected: found,
+      };
   }
 
   return {
     status: "ready",
     doSelect: {
-      onClick: async () => setIsSelecting(true)
+      onClick: async () => setIsSelecting(true),
     },
-    selected: listCurrency[0]
-  }
+    selected: listCurrency[0],
+  };
 }
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts 
b/packages/taler-wallet-webextension/src/test-utils.ts
index 7e9c5670e..e2339bff3 100644
--- a/packages/taler-wallet-webextension/src/test-utils.ts
+++ b/packages/taler-wallet-webextension/src/test-utils.ts
@@ -82,7 +82,7 @@ export function renderNodeOrBrowser(Component: any, args: 
any): void {
     document.body.removeChild(div);
   }
 }
-type RecursiveState<S> = S | (() => RecursiveState<S>)
+type RecursiveState<S> = S | (() => RecursiveState<S>);
 
 interface Mounted<T> {
   unmount: () => void;
@@ -107,12 +107,12 @@ export function mountHook<T extends object>(
   // component that's going to hold the hook
   function Component(): VNode {
     try {
-      let componentOrResult = callback()
+      let componentOrResult = callback();
       while (typeof componentOrResult === "function") {
         componentOrResult = componentOrResult();
       }
       //typecheck fails here
-      const l: Exclude<T, () => void> = componentOrResult as any
+      const l: Exclude<T, () => void> = componentOrResult as any;
       lastResult = l;
     } catch (e) {
       if (e instanceof Error) {
diff --git a/packages/taler-wallet-webextension/src/utils/index.ts 
b/packages/taler-wallet-webextension/src/utils/index.ts
index 3535910cf..2323c7b21 100644
--- a/packages/taler-wallet-webextension/src/utils/index.ts
+++ b/packages/taler-wallet-webextension/src/utils/index.ts
@@ -14,12 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import {
-  AmountJson,
-  Amounts,
-  GetExchangeTosResult,
-} from "@gnu-taler/taler-util";
-import { VNode, createElement } from "preact";
+import { createElement, VNode } from "preact";
 
 function getJsonIfOk(r: Response): Promise<any> {
   if (r.ok) {
@@ -31,7 +26,8 @@ function getJsonIfOk(r: Response): Promise<any> {
   }
 
   throw new Error(
-    `Try another server: (${r.status}) ${r.statusText || "internal server 
error"
+    `Try another server: (${r.status}) ${
+      r.statusText || "internal server error"
     }`,
   );
 }
@@ -78,140 +74,25 @@ export async function queryToSlashKeys<T>(url: string): 
Promise<T> {
   return timeout(3000, query);
 }
 
-export function buildTermsOfServiceState(
-  tos: GetExchangeTosResult,
-): TermsState {
-  const content: TermsDocument | undefined = parseTermsOfServiceContent(
-    tos.contentType,
-    tos.content,
-  );
-
-  const status: TermsStatus = buildTermsOfServiceStatus(
-    tos.content,
-    tos.acceptedEtag,
-    tos.currentEtag,
-  );
-
-  return { content, status, version: tos.currentEtag };
-}
-export function buildTermsOfServiceStatus(
-  content: string | undefined,
-  acceptedVersion: string | undefined,
-  currentVersion: string | undefined,
-): TermsStatus {
-  return !content
-    ? "notfound"
-    : !acceptedVersion
-      ? "new"
-      : acceptedVersion !== currentVersion
-        ? "changed"
-        : "accepted";
-}
-
-function parseTermsOfServiceContent(
-  type: string,
-  text: string,
-): TermsDocument | undefined {
-  if (type === "text/xml") {
-    try {
-      const document = new DOMParser().parseFromString(text, "text/xml");
-      return { type: "xml", document };
-    } catch (e) {
-      console.log(e);
-    }
-  } else if (type === "text/html") {
-    try {
-      const href = new URL(text);
-      return { type: "html", href };
-    } catch (e) {
-      console.log(e);
-    }
-  } else if (type === "text/json") {
-    try {
-      const data = JSON.parse(text);
-      return { type: "json", data };
-    } catch (e) {
-      console.log(e);
-    }
-  } else if (type === "text/pdf") {
-    try {
-      const location = new URL(text);
-      return { type: "pdf", location };
-    } catch (e) {
-      console.log(e);
-    }
-  } else if (type === "text/plain") {
-    try {
-      const content = text;
-      return { type: "plain", content };
-    } catch (e) {
-      console.log(e);
-    }
-  }
-  return undefined;
-}
-
-export type TermsState = {
-  content: TermsDocument | undefined;
-  status: TermsStatus;
-  version: string;
-};
-
-type TermsStatus = "new" | "accepted" | "changed" | "notfound";
-
-type TermsDocument =
-  | TermsDocumentXml
-  | TermsDocumentHtml
-  | TermsDocumentPlain
-  | TermsDocumentJson
-  | TermsDocumentPdf;
-
-export interface TermsDocumentXml {
-  type: "xml";
-  document: Document;
-}
-
-export interface TermsDocumentHtml {
-  type: "html";
-  href: URL;
-}
-
-export interface TermsDocumentPlain {
-  type: "plain";
-  content: string;
-}
-
-export interface TermsDocumentJson {
-  type: "json";
-  data: any;
-}
-
-export interface TermsDocumentPdf {
-  type: "pdf";
-  location: URL;
-}
-
 export type StateFunc<S> = (p: S) => VNode;
 
 export type StateViewMap<StateType extends { status: string }> = {
   [S in StateType as S["status"]]: StateFunc<S>;
 };
 
-type RecursiveState<S extends object> = S | (() => RecursiveState<S>)
+type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
 
 export function compose<SType extends { status: string }, PType>(
   name: string,
   hook: (p: PType) => RecursiveState<SType>,
   viewMap: StateViewMap<SType>,
 ): (p: PType) => VNode {
-
   function withHook(stateHook: () => RecursiveState<SType>): () => VNode {
-
     function TheComponent(): VNode {
       const state = stateHook();
 
       if (typeof state === "function") {
-        const subComponent = withHook(state)
+        const subComponent = withHook(state);
         return createElement(subComponent, {});
       }
 
@@ -225,7 +106,7 @@ export function compose<SType extends { status: string }, 
PType>(
   }
 
   return (p: PType) => {
-    const h = withHook(() => hook(p))
-    return h()
+    const h = withHook(() => hook(p));
+    return h();
   };
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts 
b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
index 527c9c8e2..0b50d9d85 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts
@@ -20,7 +20,11 @@ import { compose, StateViewMap } from "../../utils/index.js";
 import { LoadingUriView, ReadyView } from "./views.js";
 import * as wxApi from "../../wxApi.js";
 import { useComponentState } from "./state.js";
-import { ButtonHandler, SelectFieldHandler, TextFieldHandler } from 
"../../mui/handlers.js";
+import {
+  ButtonHandler,
+  SelectFieldHandler,
+  TextFieldHandler,
+} from "../../mui/handlers.js";
 
 export interface Props {
   currency: string;
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts 
b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
index 8f7920d35..f14c4c1bb 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts
@@ -20,16 +20,18 @@ import { useAsyncAsHook } from 
"../../hooks/useAsyncAsHook.js";
 import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
-export function useComponentState({ currency, onAccountAdded, onCancel }: 
Props, api: typeof wxApi): State {
+export function useComponentState(
+  { currency, onAccountAdded, onCancel }: Props,
+  api: typeof wxApi,
+): State {
   const hook = useAsyncAsHook(async () => {
     const { accounts } = await api.listKnownBankAccounts(currency);
     return { accounts };
   });
 
-  const [payto, setPayto] = useState("")
-  const [alias, setAlias] = useState("")
-  const [type, setType] = useState("")
-
+  const [payto, setPayto] = useState("");
+  const [alias, setAlias] = useState("");
+  const [type, setType] = useState("");
 
   if (!hook) {
     return {
@@ -41,31 +43,38 @@ export function useComponentState({ currency, 
onAccountAdded, onCancel }: Props,
     return {
       status: "loading-error",
       error: hook,
-    }
+    };
   }
 
   const accountType: Record<string, string> = {
     "": "Choose one account",
-    "iban": "IBAN",
-    "bitcoin": "Bitcoin",
-    "x-taler-bank": "Taler Bank"
-  }
-  const uri = parsePaytoUri(payto)
-  const found = hook.response.accounts.findIndex(a => stringifyPaytoUri(a.uri) 
=== payto) !== -1
+    iban: "IBAN",
+    bitcoin: "Bitcoin",
+    "x-taler-bank": "Taler Bank",
+  };
+  const uri = parsePaytoUri(payto);
+  const found =
+    hook.response.accounts.findIndex(
+      (a) => stringifyPaytoUri(a.uri) === payto,
+    ) !== -1;
 
   async function addAccount(): Promise<void> {
     if (!uri || found) return;
 
-    await api.addKnownBankAccounts(uri, currency, alias)
-    onAccountAdded(payto)
+    await api.addKnownBankAccounts(uri, currency, alias);
+    onAccountAdded(payto);
   }
 
-  const paytoUriError = payto === "" ? undefined
-    : !uri ? "the uri is not ok"
-      : found ? "that account is already present"
-        : undefined
+  const paytoUriError =
+    payto === ""
+      ? undefined
+      : !uri
+      ? "the uri is not ok"
+      : found
+      ? "that account is already present"
+      : undefined;
 
-  const unableToAdd = !type || !alias || paytoUriError
+  const unableToAdd = !type || !alias || paytoUriError;
 
   return {
     status: "ready",
@@ -75,27 +84,27 @@ export function useComponentState({ currency, 
onAccountAdded, onCancel }: Props,
       list: accountType,
       value: type,
       onChange: async (v) => {
-        setType(v)
-      }
+        setType(v);
+      },
     },
     alias: {
       value: alias,
       onInput: async (v) => {
-        setAlias(v)
+        setAlias(v);
       },
     },
     uri: {
       value: payto,
       error: paytoUriError,
       onInput: async (v) => {
-        setPayto(v)
-      }
+        setPayto(v);
+      },
     },
     onAccountAdded: {
-      onClick: unableToAdd ? undefined : addAccount
+      onClick: unableToAdd ? undefined : addAccount,
     },
     onCancel: {
-      onClick: async () => onCancel()
-    }
+      onClick: async () => onCancel(),
+    },
   };
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
index eb97ccf7f..81d401a70 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
@@ -17,11 +17,22 @@
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
 import { compose, StateViewMap } from "../../utils/index.js";
-import { AmountOrCurrencyErrorView, LoadingErrorView, NoAccountToDepositView, 
NoEnoughBalanceView, ReadyView } from "./views.js";
+import {
+  AmountOrCurrencyErrorView,
+  LoadingErrorView,
+  NoAccountToDepositView,
+  NoEnoughBalanceView,
+  ReadyView,
+} from "./views.js";
 import * as wxApi from "../../wxApi.js";
 import { useComponentState } from "./state.js";
 import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
-import { ButtonHandler, SelectFieldHandler, TextFieldHandler, ToggleHandler } 
from "../../mui/handlers.js";
+import {
+  ButtonHandler,
+  SelectFieldHandler,
+  TextFieldHandler,
+  ToggleHandler,
+} from "../../mui/handlers.js";
 import { AddAccountPage } from "../AddAccount/index.js";
 
 export interface Props {
@@ -31,7 +42,8 @@ export interface Props {
   onSuccess: (currency: string) => void;
 }
 
-export type State = State.Loading
+export type State =
+  | State.Loading
   | State.LoadingUriError
   | State.AmountOrCurrencyError
   | State.NoEnoughBalance
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index 87705507c..57380a632 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -14,13 +14,24 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { AmountJson, Amounts, DepositGroupFees, KnownBankAccountsInfo, 
parsePaytoUri, PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
+import {
+  AmountJson,
+  Amounts,
+  DepositGroupFees,
+  KnownBankAccountsInfo,
+  parsePaytoUri,
+  PaytoUri,
+  stringifyPaytoUri,
+} from "@gnu-taler/taler-util";
 import { useState } from "preact/hooks";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
-export function useComponentState({ amount: amountStr, currency: currencyStr, 
onCancel, onSuccess }: Props, api: typeof wxApi): State {
+export function useComponentState(
+  { amount: amountStr, currency: currencyStr, onCancel, onSuccess }: Props,
+  api: typeof wxApi,
+): State {
   const parsed = amountStr === undefined ? undefined : 
Amounts.parse(amountStr);
   const currency = parsed !== undefined ? parsed.currency : currencyStr;
 
@@ -46,8 +57,8 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
   if (!currency) {
     return {
       status: "amount-or-currency-error",
-      error: undefined
-    }
+      error: undefined,
+    };
   }
 
   if (!hook) {
@@ -60,7 +71,7 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
     return {
       status: "loading-error",
       error: hook,
-    }
+    };
   }
   const { accounts, balances } = hook.response;
 
@@ -74,13 +85,12 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
       onAccountAdded: (p: string) => {
         updateAccountFromList(p);
         setAddingAccount(false);
-        hook.retry()
+        hook.retry();
       },
       onCancel: () => {
         setAddingAccount(false);
-      }
-      ,
-    }
+      },
+    };
   }
 
   const bs = balances.filter((b) => b.available.startsWith(currency));
@@ -103,13 +113,15 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
       error: undefined,
       currency,
       onAddAccount: {
-        onClick: async () => { setAddingAccount(true) }
+        onClick: async () => {
+          setAddingAccount(true);
+        },
       },
-    }
+    };
   }
 
   const accountMap = createLabelsForBankAccount(accounts);
-  accountMap[""] = "Select one account..."
+  accountMap[""] = "Select one account...";
 
   async function updateAccountFromList(accountStr: string): Promise<void> {
     // const newSelected = !accountMap[accountStr] ? undefined : 
accountMap[accountStr];
@@ -144,18 +156,19 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
       ? Amounts.sum([fee.wire, fee.coin, fee.refresh]).amount
       : Amounts.getZero(currency);
 
-  const totalToDeposit = parsedAmount && fee !== undefined
-    ? Amounts.sub(parsedAmount, totalFee).amount
-    : Amounts.getZero(currency);
+  const totalToDeposit =
+    parsedAmount && fee !== undefined
+      ? Amounts.sub(parsedAmount, totalFee).amount
+      : Amounts.getZero(currency);
 
   const isDirty = amount !== initialValue;
   const amountError = !isDirty
     ? undefined
     : !parsedAmount
-      ? "Invalid amount"
-      : Amounts.cmp(balance, parsedAmount) === -1
-        ? `Too much, your current balance is 
${Amounts.stringifyValue(balance)}`
-        : undefined;
+    ? "Invalid amount"
+    : Amounts.cmp(balance, parsedAmount) === -1
+    ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}`
+    : undefined;
 
   const unableToDeposit =
     !parsedAmount ||
@@ -181,10 +194,11 @@ export function useComponentState({ amount: amountStr, 
currency: currencyStr, on
       value: String(amount),
       onInput: updateAmount,
       error: amountError,
-
     },
     onAddAccount: {
-      onClick: async () => { setAddingAccount(true) }
+      onClick: async () => {
+        setAddingAccount(true);
+      },
     },
     account: {
       list: accountMap,
@@ -219,22 +233,26 @@ async function getFeeForAmount(
 
 export function labelForAccountType(id: string) {
   switch (id) {
-    case "": return "Choose one";
-    case "x-taler-bank": return "Taler Bank";
-    case "bitcoin": return "Bitcoin";
-    case "iban": return "IBAN";
-    default: return id;
+    case "":
+      return "Choose one";
+    case "x-taler-bank":
+      return "Taler Bank";
+    case "bitcoin":
+      return "Bitcoin";
+    case "iban":
+      return "IBAN";
+    default:
+      return id;
   }
 }
 
 export function createLabelsForBankAccount(
   knownBankAccounts: Array<KnownBankAccountsInfo>,
 ): { [value: string]: string } {
-  const initialList: Record<string, string> = {
-  }
+  const initialList: Record<string, string> = {};
   if (!knownBankAccounts.length) return initialList;
   return knownBankAccounts.reduce((prev, cur, i) => {
-    prev[stringifyPaytoUri(cur.uri)] = cur.alias
+    prev[stringifyPaytoUri(cur.uri)] = cur.alias;
     return prev;
   }, initialList);
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
index a1d4ca85a..68df5e402 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts
@@ -19,7 +19,14 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { Amounts, Balance, BalancesResponse, DepositGroupFees, parsePaytoUri, 
stringifyPaytoUri } from "@gnu-taler/taler-util";
+import {
+  Amounts,
+  Balance,
+  BalancesResponse,
+  DepositGroupFees,
+  parsePaytoUri,
+  stringifyPaytoUri,
+} from "@gnu-taler/taler-util";
 import { expect } from "chai";
 import { mountHook } from "../../test-utils.js";
 
@@ -52,17 +59,19 @@ const nullFunction: any = () => null;
 type VoidFunction = () => void;
 
 describe("DepositPage states", () => {
-
   it("should have status 'no-enough-balance' when balance is empty", async () 
=> {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:0` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({ accounts: {} }),
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:0` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({ accounts: {} }),
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -111,25 +120,28 @@ describe("DepositPage states", () => {
     uri: parsePaytoUri("payto://iban/ES8877998399652238")!,
     kyc_completed: false,
     currency: "EUR",
-    alias: "my iban account"
+    alias: "my iban account",
   };
   const talerBankPayto = {
     uri: parsePaytoUri("payto://x-taler-bank/ES8877998399652238")!,
     kyc_completed: false,
     currency: "EUR",
-    alias: "my taler account"
+    alias: "my taler account",
   };
 
   it("should have status 'ready' but unable to deposit ", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:1` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:1` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -155,14 +167,17 @@ describe("DepositPage states", () => {
   it.skip("should not be able to deposit more than the balance ", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:1` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
-          getFeeForDeposit: withoutFee,
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:1` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
+            getFeeForDeposit: withoutFee,
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -217,14 +232,17 @@ describe("DepositPage states", () => {
   it.skip("should calculate the fee upon entering amount ", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:1` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
-          getFeeForDeposit: withSomeFee,
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:1` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
+            getFeeForDeposit: withSomeFee,
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -281,16 +299,19 @@ describe("DepositPage states", () => {
   it("should calculate the fee upon selecting account ", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:1` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({
-            accounts: [ibanPayto, talerBankPayto],
-          }),
-          getFeeForDeposit: freeJustForIBAN,
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:1` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({
+              accounts: [ibanPayto, talerBankPayto],
+            }),
+            getFeeForDeposit: freeJustForIBAN,
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -327,7 +348,6 @@ describe("DepositPage states", () => {
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
       expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
       expect(r.depositHandler.onClick).undefined;
-
     }
 
     await waitNextUpdate("");
@@ -358,7 +378,6 @@ describe("DepositPage states", () => {
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
       expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
       expect(r.depositHandler.onClick).undefined;
-
     }
 
     await waitNextUpdate("");
@@ -374,7 +393,6 @@ describe("DepositPage states", () => {
       expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
       expect(r.depositHandler.onClick).undefined;
 
-
       if (r.account.onChange === undefined) expect.fail();
       r.account.onChange(stringifyPaytoUri(talerBankPayto.uri));
     }
@@ -391,7 +409,6 @@ describe("DepositPage states", () => {
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
       expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
       expect(r.depositHandler.onClick).undefined;
-
     }
 
     await waitNextUpdate("");
@@ -414,14 +431,17 @@ describe("DepositPage states", () => {
   it.skip("should be able to deposit if has the enough balance ", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ currency, onCancel: nullFunction, onSuccess: 
nullFunction }, {
-          getBalance: async () =>
-          ({
-            balances: [{ available: `${currency}:15` }],
-          } as Partial<BalancesResponse>),
-          listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
-          getFeeForDeposit: withSomeFee,
-        } as Partial<typeof wxApi> as any),
+        useComponentState(
+          { currency, onCancel: nullFunction, onSuccess: nullFunction },
+          {
+            getBalance: async () =>
+              ({
+                balances: [{ available: `${currency}:15` }],
+              } as Partial<BalancesResponse>),
+            listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
+            getFeeForDeposit: withSomeFee,
+          } as Partial<typeof wxApi> as any,
+        ),
       );
 
     {
@@ -456,7 +476,6 @@ describe("DepositPage states", () => {
       expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
       expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
       expect(r.depositHandler.onClick).undefined;
-
     }
 
     await waitNextUpdate();
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx
index c6bff219f..b58fce8e6 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx
+++ 
b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.stories.tsx
@@ -19,20 +19,8 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { termsXml } from "../cta/termsExample.js";
 import { createExample } from "../test-utils.js";
-import { View as TestedComponent } from "./ExchangeAddConfirm.js";
-
-function parseFromString(s: string): Document {
-  if (typeof window === "undefined") {
-    return {
-      querySelector: () => ({
-        children: [],
-      }),
-    } as any;
-  }
-  return new window.DOMParser().parseFromString(s, "text/xml");
-}
+import { ExchangeAddConfirmPage as TestedComponent } from 
"./ExchangeAddConfirm.js";
 
 export default {
   title: "wallet/exchange add/confirm",
@@ -46,33 +34,12 @@ export default {
 
 export const TermsNotFound = createExample(TestedComponent, {
   url: "https://exchange.demo.taler.net/";,
-  terms: {
-    status: "notfound",
-    version: "1",
-    content: undefined,
-  },
-  onAccept: async () => undefined,
 });
 
 export const NewTerms = createExample(TestedComponent, {
   url: "https://exchange.demo.taler.net/";,
-  terms: {
-    status: "new",
-    version: "1",
-    content: undefined,
-  },
-  onAccept: async () => undefined,
 });
 
 export const TermsChanged = createExample(TestedComponent, {
   url: "https://exchange.demo.taler.net/";,
-  terms: {
-    status: "changed",
-    version: "1",
-    content: {
-      type: "xml",
-      document: parseFromString(termsXml),
-    },
-  },
-  onAccept: async () => undefined,
 });
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx
index a92ece066..b0602d1e6 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddConfirm.tsx
@@ -17,10 +17,9 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Title } from "../components/styled/index.js";
 import { useTranslationContext } from "../context/translation.js";
-import { TermsOfServiceSection } from "../cta/TermsOfServiceSection.js";
+import { TermsOfService } from "../cta/TermsOfService/index.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
 import { Button } from "../mui/Button.js";
-import { buildTermsOfServiceState, TermsState } from "../utils/index.js";
 import * as wxApi from "../wxApi.js";
 
 export interface Props {
@@ -34,69 +33,9 @@ export function ExchangeAddConfirmPage({
   onCancel,
   onConfirm,
 }: Props): VNode {
-  const detailsHook = useAsyncAsHook(async () => {
-    const tos = await wxApi.getExchangeTos(url, ["text/xml"]);
-
-    const tosState = buildTermsOfServiceState(tos);
-
-    return { tos: tosState };
-  });
-
-  const termsNotFound: TermsState = {
-    status: "notfound",
-    version: "",
-    content: undefined,
-  };
-  const terms = !detailsHook
-    ? undefined
-    : detailsHook.hasError
-    ? termsNotFound
-    : detailsHook.response.tos;
-
-  // const [errorAccepting, setErrorAccepting] = useState<string | undefined>(
-  //   undefined,
-  // );
-
-  const onAccept = async (): Promise<void> => {
-    if (!terms) return;
-    try {
-      await wxApi.setExchangeTosAccepted(url, terms.version);
-    } catch (e) {
-      if (e instanceof Error) {
-        // setErrorAccepting(e.message);
-      }
-    }
-  };
-  return (
-    <View
-      url={url}
-      onAccept={onAccept}
-      onCancel={onCancel}
-      onConfirm={onConfirm}
-      terms={terms}
-    />
-  );
-}
-
-export interface ViewProps {
-  url: string;
-  terms: TermsState | undefined;
-  onAccept: (b: boolean) => Promise<void>;
-  onCancel: () => Promise<void>;
-  onConfirm: () => Promise<void>;
-}
-
-export function View({
-  url,
-  terms,
-  onAccept: doAccept,
-  onConfirm,
-  onCancel,
-}: ViewProps): VNode {
   const { i18n } = useTranslationContext();
-  const needsReview =
-    !terms || terms.status === "changed" || terms.status === "new";
-  const [reviewed, setReviewed] = useState<boolean>(false);
+
+  const [accepted, setAccepted] = useState(false);
 
   return (
     <Fragment>
@@ -111,52 +50,27 @@ export function View({
           </a>
         </div>
       </section>
-      {terms && (
-        <TermsOfServiceSection
-          reviewed={reviewed}
-          reviewing={true}
-          terms={terms}
-          onAccept={(value) =>
-            doAccept(value).then(() => {
-              setReviewed(value);
-            })
-          }
-        />
-      )}
+
+      <TermsOfService key="terms" exchangeUrl={url} onChange={setAccepted} />
 
       <footer>
-        <Button variant="contained" color="secondary" onClick={onCancel}>
+        <Button
+          key="cancel"
+          variant="contained"
+          color="secondary"
+          onClick={onCancel}
+        >
           <i18n.Translate>Cancel</i18n.Translate>
         </Button>
-        {!terms && (
-          <Button variant="contained" disabled>
-            <i18n.Translate>Loading terms..</i18n.Translate>
-          </Button>
-        )}
-        {terms && (
-          <Fragment>
-            {needsReview && !reviewed && (
-              <Button
-                variant="contained"
-                color="success"
-                disabled
-                onClick={onConfirm}
-              >
-                <i18n.Translate>Add exchange</i18n.Translate>
-              </Button>
-            )}
-            {(terms.status === "accepted" || (needsReview && reviewed)) && (
-              <Button variant="contained" color="success" onClick={onConfirm}>
-                <i18n.Translate>Add exchange</i18n.Translate>
-              </Button>
-            )}
-            {terms.status === "notfound" && (
-              <Button variant="contained" color="warning" onClick={onConfirm}>
-                <i18n.Translate>Add exchange anyway</i18n.Translate>
-              </Button>
-            )}
-          </Fragment>
-        )}
+        <Button
+          key="add"
+          variant="contained"
+          color="success"
+          disabled={!accepted}
+          onClick={onConfirm}
+        >
+          <i18n.Translate>Add exchange</i18n.Translate>
+        </Button>
       </footer>
     </Fragment>
   );
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
index 9603b3d2c..06d519268 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
@@ -17,13 +17,12 @@
 import {
   DenomOperationMap,
   ExchangeFullDetails,
-  ExchangeListItem, FeeDescriptionPair
+  ExchangeListItem,
+  FeeDescriptionPair,
 } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
-import {
-  State as SelectExchangeState
-} from "../../hooks/useSelectedExchange.js";
+import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
@@ -32,12 +31,12 @@ import {
   ComparingView,
   ErrorLoadingView,
   NoExchangesView,
-  ReadyView
+  ReadyView,
 } from "./views.js";
 
 export interface Props {
-  list: ExchangeListItem[],
-  currentExchange: string,
+  list: ExchangeListItem[];
+  currentExchange: string;
   onCancel: () => Promise<void>;
   onSelection: (exchange: string) => Promise<void>;
 }
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
index 954e52239..e1b270a42 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
@@ -25,9 +25,13 @@ export function useComponentState(
   { onCancel, onSelection, list: exchanges, currentExchange }: Props,
   api: typeof wxApi,
 ): State {
-  const initialValue = exchanges.findIndex(e => e.exchangeBaseUrl === 
currentExchange);
+  const initialValue = exchanges.findIndex(
+    (e) => e.exchangeBaseUrl === currentExchange,
+  );
   if (initialValue === -1) {
-    throw Error(`wrong usage of ExchangeSelection component, currentExchange 
'${currentExchange}' is not in the list of exchanges`)
+    throw Error(
+      `wrong usage of ExchangeSelection component, currentExchange 
'${currentExchange}' is not in the list of exchanges`,
+    );
   }
   const [value, setValue] = useState(String(initialValue));
 
@@ -113,7 +117,7 @@ export function useComponentState(
     withdraw: createPairTimeline(
       selected.denomFees.withdraw,
       original.denomFees.withdraw,
-    )
+    ),
   };
 
   return {
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
index 6b753e215..d39aa3878 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
@@ -14,24 +14,20 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import {
-  Amounts,
-  FeeDescription,
-  FeeDescriptionPair,
-} from "@gnu-taler/taler-util";
+import { FeeDescription, FeeDescriptionPair } from "@gnu-taler/taler-util";
 import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Amount } from "../../components/Amount.js";
 import { LoadingError } from "../../components/LoadingError.js";
 import { SelectList } from "../../components/SelectList.js";
-import { Input, LinkPrimary, SvgIcon } from "../../components/styled/index.js";
+import { Input, SvgIcon } from "../../components/styled/index.js";
 import { Time } from "../../components/Time.js";
 import { useTranslationContext } from "../../context/translation.js";
+import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { Button } from "../../mui/Button.js";
 import arrowDown from "../../svg/chevron-down.svg";
 import { State } from "./index.js";
-import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 
 const ButtonGroup = styled.div`
   & > button {
@@ -39,6 +35,16 @@ const ButtonGroup = styled.div`
     margin-right: 8px;
   }
 `;
+const ButtonGroupFooter = styled.div`
+  & {
+    display: flex;
+    justify-content: space-between;
+  }
+  & > button {
+    margin-left: 8px;
+    margin-right: 8px;
+  }
+`;
 
 const FeeDescriptionTable = styled.table`
   & {
@@ -343,10 +349,10 @@ export function ComparingView({
         </table>
       </section>
       <section>
-        <ButtonGroup>
-          <LinkPrimary>Privacy policy</LinkPrimary>
-          <LinkPrimary>Terms of service</LinkPrimary>
-        </ButtonGroup>
+        <ButtonGroupFooter>
+          <Button variant="outlined">Privacy policy</Button>
+          <Button variant="outlined">Terms of service</Button>
+        </ButtonGroupFooter>
       </section>
     </Container>
   );
@@ -609,10 +615,10 @@ export function ReadyView({
         </FeeDescriptionTable>
       </section>
       <section>
-        <ButtonGroup>
-          <LinkPrimary>Privacy policy</LinkPrimary>
-          <LinkPrimary>Terms of service</LinkPrimary>
-        </ButtonGroup>
+        <ButtonGroupFooter>
+          <Button variant="outlined">Privacy policy</Button>
+          <Button variant="outlined">Terms of service</Button>
+        </ButtonGroupFooter>
       </section>
     </Container>
   );
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 28ee229eb..56e610e8a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -36,7 +36,7 @@ import { useBackupDeviceName } from 
"../hooks/useBackupDeviceName.js";
 import { useAutoOpenPermissions } from "../hooks/useAutoOpenPermissions.js";
 import { ToggleHandler } from "../mui/handlers.js";
 import { Pages } from "../NavigationBar.js";
-import { buildTermsOfServiceStatus } from "../utils/index.js";
+import { buildTermsOfServiceStatus } from "../cta/TermsOfService/utils.js";
 import * as wxApi from "../wxApi.js";
 import { platform } from "../platform/api.js";
 import { useClipboardPermissions } from "../hooks/useClipboardPermissions.js";
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 1b0f67346..e0a1ee238 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -24,8 +24,16 @@
 import {
   AcceptExchangeTosRequest,
   AcceptManualWithdrawalResult,
-  AcceptPeerPullPaymentRequest, AcceptPeerPullPaymentResponse, 
AcceptPeerPushPaymentRequest, AcceptPeerPushPaymentResponse, AcceptTipRequest, 
AcceptTipResponse, AcceptWithdrawalResponse,
-  AddExchangeRequest, AddKnownBankAccountsRequest, AmountString,
+  AcceptPeerPullPaymentRequest,
+  AcceptPeerPullPaymentResponse,
+  AcceptPeerPushPaymentRequest,
+  AcceptPeerPushPaymentResponse,
+  AcceptTipRequest,
+  AcceptTipResponse,
+  AcceptWithdrawalResponse,
+  AddExchangeRequest,
+  AddKnownBankAccountsRequest,
+  AmountString,
   ApplyRefundResponse,
   BalancesResponse,
   CheckPeerPullPaymentRequest,
@@ -37,7 +45,12 @@ import {
   CoreApiResponse,
   CreateDepositGroupRequest,
   CreateDepositGroupResponse,
-  DeleteTransactionRequest, DepositGroupFees, ExchangeFullDetails, 
ExchangesListResponse, ForgetKnownBankAccountsRequest, GetExchangeTosResult,
+  DeleteTransactionRequest,
+  DepositGroupFees,
+  ExchangeFullDetails,
+  ExchangesListResponse,
+  ForgetKnownBankAccountsRequest,
+  GetExchangeTosResult,
   GetExchangeWithdrawalInfo,
   GetFeeForDepositRequest,
   GetWithdrawalDetailsForUriRequest,
@@ -47,7 +60,9 @@ import {
   InitiatePeerPushPaymentResponse,
   KnownBankAccounts,
   Logger,
-  NotificationType, PaytoUri, PrepareDepositRequest,
+  NotificationType,
+  PaytoUri,
+  PrepareDepositRequest,
   PrepareDepositResponse,
   PreparePayResult,
   PrepareRefundRequest,
@@ -55,9 +70,13 @@ import {
   PrepareTipRequest,
   PrepareTipResult,
   RetryTransactionRequest,
-  SetWalletDeviceIdRequest, stringifyPaytoUri, Transaction,
-  TransactionsResponse, WalletCoreVersion,
-  WalletDiagnostics, WithdrawUriInfoResponse
+  SetWalletDeviceIdRequest,
+  stringifyPaytoUri,
+  Transaction,
+  TransactionsResponse,
+  WalletCoreVersion,
+  WalletDiagnostics,
+  WithdrawUriInfoResponse,
 } from "@gnu-taler/taler-util";
 import {
   AddBackupProviderRequest,
@@ -66,7 +85,7 @@ import {
   PendingOperationsResponse,
   RemoveBackupProviderRequest,
   TalerError,
-  WalletContractData
+  WalletContractData,
 } from "@gnu-taler/taler-wallet-core";
 import { MessageFromBackend, platform } from "./platform/api.js";
 
@@ -268,13 +287,13 @@ export function addKnownBankAccounts(
   return callBackend("addKnownBankAccounts", {
     payto: stringifyPaytoUri(payto),
     currency,
-    alias
+    alias,
   } as AddKnownBankAccountsRequest);
 }
-export function forgetKnownBankAccounts(
-  payto: string,
-): Promise<void> {
-  return callBackend("forgetKnownBankAccounts", { payto } as 
ForgetKnownBankAccountsRequest);
+export function forgetKnownBankAccounts(payto: string): Promise<void> {
+  return callBackend("forgetKnownBankAccounts", {
+    payto,
+  } as ForgetKnownBankAccountsRequest);
 }
 
 /**

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