gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (23bb82f0 -> 4ca38113)


From: gnunet
Subject: [taler-wallet-core] branch master updated (23bb82f0 -> 4ca38113)
Date: Thu, 18 Aug 2022 21:02:25 +0200

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

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

    from 23bb82f0 disable button when wating for response
     new d1980c39 moved wireInfo and denomInfo into taler-util so it can be 
used from the ui
     new 4ca38113 first iteration of exchange selection: added information in 
the exchangeDetails response from core

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


Summary of changes:
 packages/taler-util/src/walletTypes.ts             | 157 ++++++++++++
 .../src/crypto/cryptoImplementation.ts             |   9 +-
 packages/taler-wallet-core/src/db.ts               |  65 +----
 .../src/operations/backup/import.ts                |  10 +-
 .../taler-wallet-core/src/operations/deposits.ts   |   2 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |   7 +-
 .../taler-wallet-core/src/operations/withdraw.ts   |  19 +-
 packages/taler-wallet-core/src/wallet.ts           |  11 +
 .../src/NavigationBar.tsx                          |   1 +
 .../src/cta/Withdraw/test.ts                       |  12 +
 .../src/wallet/Application.tsx                     |   2 +
 .../src/wallet/ExchangeSelection.stories.tsx       |  85 +++++++
 .../src/wallet/ExchangeSelection.tsx               | 282 +++++++++++++++++++++
 .../src/wallet/Settings.stories.tsx                |   4 +-
 .../src/wallet/index.stories.tsx                   |   2 +
 15 files changed, 595 insertions(+), 73 deletions(-)
 create mode 100644 
packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx
 create mode 100644 
packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx

diff --git a/packages/taler-util/src/walletTypes.ts 
b/packages/taler-util/src/walletTypes.ts
index eac9cf7d..7b482c60 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -44,14 +44,17 @@ import {
   codecForAny,
   buildCodecForUnion,
   codecForNumber,
+  codecForMap,
 } from "./codec.js";
 import {
   AmountString,
+  AuditorDenomSig,
   codecForContractTerms,
   CoinEnvelope,
   ContractTerms,
   DenominationPubKey,
   DenomKeyType,
+  ExchangeAuditor,
   UnblindedSignature,
 } from "./talerTypes.js";
 import { OrderShortInfo, codecForOrderShortInfo } from 
"./transactionsTypes.js";
@@ -580,13 +583,164 @@ export interface ExchangeTos {
   contentType?: string;
   content?: string;
 }
+
+/**
+ * Wire fee for one wire method
+ */
+export interface WireFee {
+  /**
+   * Fee for wire transfers.
+   */
+  wireFee: AmountJson;
+
+  /**
+   * Fees to close and refund a reserve.
+   */
+  closingFee: AmountJson;
+
+  /**
+   * Fees for inter-exchange transfers from P2P payments.
+   */
+  wadFee: AmountJson;
+
+  /**
+   * Start date of the fee.
+   */
+  startStamp: TalerProtocolTimestamp;
+
+  /**
+   * End date of the fee.
+   */
+  endStamp: TalerProtocolTimestamp;
+
+  /**
+   * Signature made by the exchange master key.
+   */
+  sig: string;
+}
+
+/**
+ * Information about one of the exchange's bank accounts.
+ */
+export interface ExchangeAccount {
+  payto_uri: string;
+  master_sig: string;
+}
+
+export type WireFeeMap = { [wireMethod: string]: WireFee[] }
+export interface WireInfo {
+  feesForType: WireFeeMap;
+  accounts: ExchangeAccount[];
+}
+
+const codecForExchangeAccount = (): Codec<ExchangeAccount> =>
+  buildCodecForObject<ExchangeAccount>()
+    .property("payto_uri", codecForString())
+    .property("master_sig", codecForString())
+    .build("codecForExchangeAccount");
+
+
+const codecForWireFee = (): Codec<WireFee> =>
+  buildCodecForObject<WireFee>()
+    .property("sig", codecForString())
+    .property("wireFee", codecForAmountJson())
+    .property("wadFee", codecForAmountJson())
+    .property("closingFee", codecForAmountJson())
+    .property("startStamp", codecForTimestamp)
+    .property("endStamp", codecForTimestamp)
+    .build("codecForWireFee");
+
+const codecForWireInfo = (): Codec<WireInfo> =>
+  buildCodecForObject<WireInfo>()
+    .property("feesForType", codecForMap(codecForList(codecForWireFee())))
+    .property("accounts", codecForList(codecForExchangeAccount()))
+    .build("codecForWireInfo");
+
+const codecForDenominationInfo = (): Codec<DenominationInfo> =>
+  buildCodecForObject<DenominationInfo>()
+    .property("denomPubHash", (codecForString()))
+    .property("value", (codecForAmountJson()))
+    .property("feeWithdraw", (codecForAmountJson()))
+    .property("feeDeposit", (codecForAmountJson()))
+    .property("feeRefresh", (codecForAmountJson()))
+    .property("feeRefund", (codecForAmountJson()))
+    .property("stampStart", (codecForTimestamp))
+    .property("stampExpireWithdraw", (codecForTimestamp))
+    .property("stampExpireLegal", (codecForTimestamp))
+    .property("stampExpireDeposit", (codecForTimestamp))
+    .build("codecForDenominationInfo");
+
+
+export interface DenominationInfo {
+  value: AmountJson;
+  denomPubHash: string;
+  /**
+   * Fee for withdrawing.
+   */
+  feeWithdraw: AmountJson;
+
+  /**
+   * Fee for depositing.
+   */
+  feeDeposit: AmountJson;
+
+  /**
+   * Fee for refreshing.
+   */
+  feeRefresh: AmountJson;
+
+  /**
+   * Fee for refunding.
+   */
+  feeRefund: AmountJson;
+
+  /**
+   * Validity start date of the denomination.
+   */
+  stampStart: TalerProtocolTimestamp;
+
+  /**
+   * Date after which the currency can't be withdrawn anymore.
+   */
+  stampExpireWithdraw: TalerProtocolTimestamp;
+
+  /**
+   * Date after the denomination officially doesn't exist anymore.
+   */
+  stampExpireLegal: TalerProtocolTimestamp;
+
+  /**
+   * Data after which coins of this denomination can't be deposited anymore.
+   */
+  stampExpireDeposit: TalerProtocolTimestamp;
+
+}
+
 export interface ExchangeListItem {
   exchangeBaseUrl: string;
   currency: string;
   paytoUris: string[];
   tos: ExchangeTos;
+  auditors: ExchangeAuditor[];
+  wireInfo: WireInfo;
+  denominations: DenominationInfo[];
 }
 
+
+const codecForAuditorDenomSig = (): Codec<AuditorDenomSig> =>
+  buildCodecForObject<AuditorDenomSig>()
+    .property("denom_pub_h", codecForString())
+    .property("auditor_sig", codecForString())
+    .build("AuditorDenomSig");
+
+const codecForExchangeAuditor = (): Codec<ExchangeAuditor> =>
+  buildCodecForObject<ExchangeAuditor>()
+    .property("auditor_pub", codecForString())
+    .property("auditor_url", codecForString())
+    .property("denomination_keys", codecForList(codecForAuditorDenomSig()))
+    .build("codecForExchangeAuditor");
+
+
 const codecForExchangeTos = (): Codec<ExchangeTos> =>
   buildCodecForObject<ExchangeTos>()
     .property("acceptedVersion", codecOptional(codecForString()))
@@ -601,6 +755,9 @@ export const codecForExchangeListItem = (): 
Codec<ExchangeListItem> =>
     .property("exchangeBaseUrl", codecForString())
     .property("paytoUris", codecForList(codecForString()))
     .property("tos", codecForExchangeTos())
+    .property("auditors", codecForList(codecForExchangeAuditor()))
+    .property("wireInfo", codecForWireInfo())
+    .property("denominations", codecForList(codecForDenominationInfo()))
     .build("ExchangeListItem");
 
 export const codecForExchangesListResponse = (): Codec<ExchangesListRespose> =>
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index edb9cdcc..099bf09f 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -76,11 +76,12 @@ import {
   TalerProtocolTimestamp,
   TalerSignaturePurpose,
   UnblindedSignature,
+  WireFee,
   WithdrawalPlanchet,
 } from "@gnu-taler/taler-util";
 import bigint from "big-integer";
 // FIXME: Crypto should not use DB Types!
-import { DenominationRecord, WireFee } from "../db.js";
+import { DenominationRecord } from "../db.js";
 import {
   CreateRecoupRefreshReqRequest,
   CreateRecoupReqRequest,
@@ -1045,10 +1046,10 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
       };
 
       if (depositInfo.requiredMinimumAge != null) {
-             s.minimum_age_sig = minimumAgeSig;
-             s.age_commitment = 
depositInfo.ageCommitmentProof?.commitment.publicKeys;
+        s.minimum_age_sig = minimumAgeSig;
+        s.age_commitment = 
depositInfo.ageCommitmentProof?.commitment.publicKeys;
       } else if (depositInfo.ageCommitmentProof) {
-             (s as any).h_age_commitment = hAgeCommitment;
+        (s as any).h_age_commitment = hAgeCommitment;
       }
 
       return s;
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 8f558abd..a34a09f7 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -44,6 +44,7 @@ import {
   PayCoinSelection,
   PeerContractTerms,
   Location,
+  WireInfo,
 } from "@gnu-taler/taler-util";
 import { RetryInfo } from "./util/retries.js";
 import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
@@ -392,11 +393,6 @@ export interface ExchangeDetailsRecord {
   wireInfo: WireInfo;
 }
 
-export interface WireInfo {
-  feesForType: { [wireMethod: string]: WireFee[] };
-
-  accounts: ExchangeBankAccount[];
-}
 
 export interface ExchangeDetailsPointer {
   masterPublicKey: string;
@@ -926,41 +922,6 @@ export interface RefreshSessionRecord {
   norevealIndex?: number;
 }
 
-/**
- * Wire fee for one wire method as stored in the
- * wallet's database.
- */
-export interface WireFee {
-  /**
-   * Fee for wire transfers.
-   */
-  wireFee: AmountJson;
-
-  /**
-   * Fees to close and refund a reserve.
-   */
-  closingFee: AmountJson;
-
-  /**
-   * Fees for inter-exchange transfers from P2P payments.
-   */
-  wadFee: AmountJson;
-
-  /**
-   * Start date of the fee.
-   */
-  startStamp: TalerProtocolTimestamp;
-
-  /**
-   * End date of the fee.
-   */
-  endStamp: TalerProtocolTimestamp;
-
-  /**
-   * Signature made by the exchange master key.
-   */
-  sig: string;
-}
 
 export enum RefundState {
   Failed = "failed",
@@ -1225,9 +1186,9 @@ export const WALLET_BACKUP_STATE_KEY = 
"walletBackupState";
  */
 export type ConfigRecord =
   | {
-      key: typeof WALLET_BACKUP_STATE_KEY;
-      value: WalletBackupConfState;
-    }
+    key: typeof WALLET_BACKUP_STATE_KEY;
+    value: WalletBackupConfState;
+  }
   | { key: "currencyDefaultsApplied"; value: boolean };
 
 export interface WalletBackupConfState {
@@ -1444,17 +1405,17 @@ export enum BackupProviderStateTag {
 
 export type BackupProviderState =
   | {
-      tag: BackupProviderStateTag.Provisional;
-    }
+    tag: BackupProviderStateTag.Provisional;
+  }
   | {
-      tag: BackupProviderStateTag.Ready;
-      nextBackupTimestamp: TalerProtocolTimestamp;
-    }
+    tag: BackupProviderStateTag.Ready;
+    nextBackupTimestamp: TalerProtocolTimestamp;
+  }
   | {
-      tag: BackupProviderStateTag.Retrying;
-      retryInfo: RetryInfo;
-      lastError?: TalerErrorDetail;
-    };
+    tag: BackupProviderStateTag.Retrying;
+    retryInfo: RetryInfo;
+    lastError?: TalerErrorDetail;
+  };
 
 export interface BackupProviderTerms {
   supportedProtocolVersion: string;
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts 
b/packages/taler-wallet-core/src/operations/backup/import.ts
index f26c4277..57d7449e 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -31,6 +31,7 @@ import {
   RefreshReason,
   TalerProtocolTimestamp,
   WalletBackupContentV1,
+  WireInfo,
 } from "@gnu-taler/taler-util";
 import {
   AbortStatus,
@@ -50,7 +51,6 @@ import {
   WalletContractData,
   WalletRefundItem,
   WalletStoresV1,
-  WireInfo,
 } from "../../db.js";
 import { InternalWalletState } from "../../internal-wallet-state.js";
 import {
@@ -341,7 +341,7 @@ export async function importBackup(
           }
           const denomPubHash =
             cryptoComp.rsaDenomPubToHash[
-              backupDenomination.denom_pub.rsa_public_key
+            backupDenomination.denom_pub.rsa_public_key
             ];
           checkLogicInvariant(!!denomPubHash);
           const existingDenom = await tx.denominations.get([
@@ -427,7 +427,7 @@ export async function importBackup(
         }
 
 
-      // FIXME: import reserves with new schema
+        // FIXME: import reserves with new schema
 
         // for (const backupReserve of backupExchangeDetails.reserves) {
         //   const reservePub =
@@ -560,7 +560,7 @@ export async function importBackup(
             const amount = Amounts.parseOrThrow(parsedContractTerms.amount);
             const contractTermsHash =
               cryptoComp.proposalIdToContractTermsHash[
-                backupProposal.proposal_id
+              backupProposal.proposal_id
               ];
             let maxWireFee: AmountJson;
             if (parsedContractTerms.max_wire_fee) {
@@ -706,7 +706,7 @@ export async function importBackup(
           const amount = Amounts.parseOrThrow(parsedContractTerms.amount);
           const contractTermsHash =
             cryptoComp.proposalIdToContractTermsHash[
-              backupPurchase.proposal_id
+            backupPurchase.proposal_id
             ];
           let maxWireFee: AmountJson;
           if (parsedContractTerms.max_wire_fee) {
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index a016cb8e..734bc4c2 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -44,7 +44,7 @@ import {
   TrackDepositGroupResponse,
   URL,
 } from "@gnu-taler/taler-util";
-import { DepositGroupRecord, OperationStatus, WireFee } from "../db.js";
+import { DepositGroupRecord, OperationStatus } from "../db.js";
 import { InternalWalletState } from "../internal-wallet-state.js";
 import { selectPayCoins } from "../util/coinSelection.js";
 import { readSuccessResponseJsonOrThrow } from "../util/http.js";
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 007dad68..6f8da5ae 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -44,6 +44,9 @@ import {
   TalerProtocolDuration,
   TalerProtocolTimestamp,
   URL,
+  WireFee,
+  WireFeeMap,
+  WireInfo,
 } from "@gnu-taler/taler-util";
 import {
   DenominationRecord,
@@ -51,8 +54,6 @@ import {
   ExchangeDetailsRecord,
   ExchangeRecord,
   WalletStoresV1,
-  WireFee,
-  WireInfo,
 } from "../db.js";
 import { TalerError } from "../errors.js";
 import { InternalWalletState, TrustInfo } from "../internal-wallet-state.js";
@@ -276,7 +277,7 @@ async function validateWireInfo(
       throw Error("exchange acct signature invalid");
     }
   }
-  const feesForType: { [wireMethod: string]: WireFee[] } = {};
+  const feesForType: WireFeeMap = {};
   for (const wireMethod of Object.keys(wireInfo.fees)) {
     const feeList: WireFee[] = [];
     for (const x of wireInfo.fees[wireMethod]) {
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index 484b9b96..721a043d 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -241,7 +241,7 @@ export function selectWithdrawalDenominations(
   for (const d of denoms) {
     let count = 0;
     const cost = Amounts.add(d.value, d.feeWithdraw).amount;
-    for (;;) {
+    for (; ;) {
       if (Amounts.cmp(remaining, cost) < 0) {
         break;
       }
@@ -898,8 +898,7 @@ export async function updateWithdrawalDenoms(
         denom.verificationStatus === DenominationVerificationStatus.Unverified
       ) {
         logger.trace(
-          `Validating denomination (${current + 1}/${
-            denominations.length
+          `Validating denomination (${current + 1}/${denominations.length
           }) signature of ${denom.denomPubHash}`,
         );
         let valid = false;
@@ -1026,7 +1025,7 @@ async function queryReserve(
     if (
       resp.status === 404 &&
       result.talerErrorResponse.code ===
-        TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
+      TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN
     ) {
       ws.notify({
         type: NotificationType.ReserveNotYetFound,
@@ -1316,7 +1315,7 @@ export async function getExchangeWithdrawalInfo(
     ) {
       logger.warn(
         `wallet's support for exchange protocol version 
${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` +
-          `(exchange has ${exchangeDetails.protocolVersion}), checking for 
updates`,
+        `(exchange has ${exchangeDetails.protocolVersion}), checking for 
updates`,
       );
     }
   }
@@ -1395,12 +1394,17 @@ export async function getWithdrawalDetailsForUri(
     .mktx((x) => ({
       exchanges: x.exchanges,
       exchangeDetails: x.exchangeDetails,
+      denominations: x.denominations,
     }))
     .runReadOnly(async (tx) => {
       const exchangeRecords = await tx.exchanges.iter().toArray();
       for (const r of exchangeRecords) {
         const details = await ws.exchangeOps.getExchangeDetails(tx, r.baseUrl);
-        if (details) {
+        const denominations = await tx.denominations.indexes
+          .byExchangeBaseUrl.iter(r.baseUrl).toArray();
+        if (details && denominations) {
+
+
           exchanges.push({
             exchangeBaseUrl: details.exchangeBaseUrl,
             currency: details.currency,
@@ -1411,6 +1415,9 @@ export async function getWithdrawalDetailsForUri(
               content: details.termsOfServiceText,
             },
             paytoUris: details.wireInfo.accounts.map((x) => x.payto_uri),
+            auditors: details.auditors,
+            wireInfo: details.wireInfo,
+            denominations: denominations
           });
         }
       }
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 1b6b5669..593d2e0f 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -553,6 +553,7 @@ async function getExchanges(
     .mktx((x) => ({
       exchanges: x.exchanges,
       exchangeDetails: x.exchangeDetails,
+      denominations: x.denominations,
     }))
     .runReadOnly(async (tx) => {
       const exchangeRecords = await tx.exchanges.iter().toArray();
@@ -567,6 +568,13 @@ async function getExchanges(
           continue;
         }
 
+        const denominations = await tx.denominations.indexes
+          .byExchangeBaseUrl.iter(r.baseUrl).toArray();
+
+        if (!denominations) {
+          continue;
+        }
+
         exchanges.push({
           exchangeBaseUrl: r.baseUrl,
           currency,
@@ -577,6 +585,9 @@ async function getExchanges(
             content: exchangeDetails.termsOfServiceText,
           },
           paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
+          auditors: exchangeDetails.auditors,
+          wireInfo: exchangeDetails.wireInfo,
+          denominations: denominations,
         });
       }
     });
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx 
b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index 70fb7bdc..42a365f8 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -98,6 +98,7 @@ export const Pages = {
   receiveCash: pageDefinition<{ amount?: string 
}>("/destination/get/:amount?"),
   dev: "/dev",
 
+  exchanges: "/exchanges",
   backup: "/backup",
   backupProviderDetail: pageDefinition<{ pid: string }>(
     "/backup/provider/:pid",
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index 5917be09..dd3f6c9c 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -37,6 +37,18 @@ const exchanges: ExchangeListItem[] = [
     tos: {
       acceptedVersion: "",
     },
+    auditors: [
+      {
+        auditor_pub: "pubpubpubpubpub",
+        auditor_url: "https://audotor.taler.net";,
+        denomination_keys: [],
+      },
+    ],
+    denominations: [{} as any],
+    wireInfo: {
+      accounts: [],
+      feesForType: {},
+    },
   },
 ];
 
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 6c08ecb7..1f375a82 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -58,6 +58,7 @@ import {
   DestinationSelectionSendCash,
 } from "./DestinationSelection.js";
 import { Amounts } from "@gnu-taler/taler-util";
+import { ExchangeSelection } from "./ExchangeSelection.js";
 
 export function Application(): VNode {
   const [globalNotification, setGlobalNotification] = useState<
@@ -141,6 +142,7 @@ export function Application(): VNode {
                   )
                 }
               />
+              <Route path={Pages.exchanges} component={ExchangeSelection} />
               <Route
                 path={Pages.sendCash.pattern}
                 component={DestinationSelectionSendCash}
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx
new file mode 100644
index 00000000..b99c6c01
--- /dev/null
+++ 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx
@@ -0,0 +1,85 @@
+/*
+ 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 { TalerProtocolTimestamp } from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils.js";
+import { ExchangeSelectionView } from "./ExchangeSelection.js";
+
+export default {
+  title: "wallet/select exchange",
+};
+
+const exchangeList = [
+  {
+    currency: "KUDOS",
+    exchangeBaseUrl: "https://exchange.demo.taler.net";,
+    paytoUris: [],
+    tos: {},
+    auditors: [
+      {
+        auditor_pub: "pubpubpubpubpub",
+        auditor_url: "https://audotor.taler.net";,
+        denomination_keys: [],
+      },
+    ],
+    denominations: [
+      {
+        stampStart: TalerProtocolTimestamp.never(),
+        stampExpireWithdraw: TalerProtocolTimestamp.never(),
+        stampExpireLegal: TalerProtocolTimestamp.never(),
+        stampExpireDeposit: TalerProtocolTimestamp.never(),
+      },
+    ],
+    wireInfo: {
+      accounts: [],
+      feesForType: {},
+    },
+  },
+  {
+    currency: "ARS",
+    exchangeBaseUrl: "https://exchange.taler.ar";,
+    paytoUris: [],
+    tos: {},
+    auditors: [
+      {
+        auditor_pub: "pubpubpubpubpub",
+        auditor_url: "https://audotor.taler.net";,
+        denomination_keys: [],
+      },
+    ],
+    denominations: [
+      {
+        stampStart: TalerProtocolTimestamp.never(),
+        stampExpireWithdraw: TalerProtocolTimestamp.never(),
+        stampExpireLegal: TalerProtocolTimestamp.never(),
+        stampExpireDeposit: TalerProtocolTimestamp.never(),
+      } as any,
+    ],
+    wireInfo: {
+      accounts: [],
+      feesForType: {},
+    },
+  },
+];
+
+export const Listing = createExample(ExchangeSelectionView, {
+  exchanges: exchangeList,
+});
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx
new file mode 100644
index 00000000..1fa92142
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx
@@ -0,0 +1,282 @@
+/*
+ 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 {
+  AbsoluteTime,
+  ExchangeListItem,
+  TalerProtocolTimestamp,
+} from "@gnu-taler/taler-util";
+import { styled } from "@linaria/react";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Loading } from "../components/Loading.js";
+import { LoadingError } from "../components/LoadingError.js";
+import { SelectList } from "../components/SelectList.js";
+import { Input, LinkPrimary } from "../components/styled/index.js";
+import { Time } from "../components/Time.js";
+import { useTranslationContext } from "../context/translation.js";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
+import { Button } from "../mui/Button.js";
+import * as wxApi from "../wxApi.js";
+
+const Container = styled.div`
+  display: flex;
+  flex-direction: column;
+  & > * {
+    margin-bottom: 20px;
+  }
+`;
+
+interface Props {
+  initialValue?: number;
+  exchanges: ExchangeListItem[];
+  onSelected: (exchange: string) => void;
+}
+
+const ButtonGroup = styled.div`
+  & > button {
+    margin-left: 8px;
+    margin-right: 8px;
+  }
+`;
+
+export function ExchangeSelection(): VNode {
+  const hook = useAsyncAsHook(wxApi.listExchanges);
+  const { i18n } = useTranslationContext();
+  if (!hook) {
+    return <Loading />;
+  }
+  if (hook.hasError) {
+    return (
+      <LoadingError
+        error={hook}
+        title={<i18n.Translate>Could not load list of 
exchange</i18n.Translate>}
+      />
+    );
+  }
+  return (
+    <ExchangeSelectionView
+      exchanges={hook.response.exchanges}
+      onSelected={(exchange) => alert(`ok, selected: ${exchange}`)}
+    />
+  );
+}
+
+export function ExchangeSelectionView({
+  initialValue,
+  exchanges,
+  onSelected,
+}: Props): VNode {
+  const list: Record<string, string> = {};
+  exchanges.forEach((e, i) => (list[String(i)] = e.exchangeBaseUrl));
+
+  const [value, setValue] = useState(String(initialValue || 0));
+  const { i18n } = useTranslationContext();
+
+  if (!exchanges.length) {
+    return <div>no exchanges for listing, please add one</div>;
+  }
+
+  const current = exchanges[Number(value)];
+
+  const hasChange = value !== current.exchangeBaseUrl;
+
+  function nearestTimestamp(
+    first: TalerProtocolTimestamp,
+    second: TalerProtocolTimestamp,
+  ): TalerProtocolTimestamp {
+    const f = AbsoluteTime.fromTimestamp(first);
+    const s = AbsoluteTime.fromTimestamp(second);
+    const a = AbsoluteTime.min(f, s);
+    return AbsoluteTime.toTimestamp(a);
+  }
+
+  let nextFeeUpdate = TalerProtocolTimestamp.never();
+
+  nextFeeUpdate = Object.values(current.wireInfo.feesForType).reduce(
+    (prev, cur) => {
+      return cur.reduce((p, c) => nearestTimestamp(p, c.endStamp), prev);
+    },
+    nextFeeUpdate,
+  );
+
+  nextFeeUpdate = current.denominations.reduce((prev, cur) => {
+    return [
+      cur.stampExpireWithdraw,
+      cur.stampExpireLegal,
+      cur.stampExpireDeposit,
+    ].reduce(nearestTimestamp, prev);
+  }, nextFeeUpdate);
+
+  return (
+    <Container>
+      <h2>
+        <i18n.Translate>Service fee description</i18n.Translate>
+      </h2>
+
+      <section>
+        <div
+          style={{
+            display: "flex",
+            flexWrap: "wrap",
+            alignItems: "center",
+            justifyContent: "space-between",
+          }}
+        >
+          <p>
+            <Input>
+              <SelectList
+                label={<i18n.Translate>Known exchanges</i18n.Translate>}
+                list={list}
+                name="lang"
+                value={value}
+                onChange={(v) => setValue(v)}
+              />
+            </Input>
+          </p>
+          {hasChange ? (
+            <ButtonGroup>
+              <Button
+                variant="outlined"
+                onClick={async () => {
+                  setValue(current.exchangeBaseUrl);
+                }}
+              >
+                Reset
+              </Button>
+              <Button
+                variant="contained"
+                onClick={async () => {
+                  onSelected(value);
+                }}
+              >
+                Use this exchange
+              </Button>
+            </ButtonGroup>
+          ) : (
+            <Button
+              variant="outlined"
+              onClick={async () => {
+                null;
+              }}
+            >
+              Close
+            </Button>
+          )}
+        </div>
+      </section>
+      <section>
+        <dl>
+          <dt>Auditors</dt>
+          {current.auditors.map((a) => {
+            <dd>{a.auditor_url}</dd>;
+          })}
+        </dl>
+        <table>
+          <tr>
+            <td>currency</td>
+            <td>{current.currency}</td>
+          </tr>
+          <tr>
+            <td>next fee update</td>
+            <td>
+              {
+                <Time
+                  timestamp={AbsoluteTime.fromTimestamp(nextFeeUpdate)}
+                  format="dd MMMM yyyy, HH:mm"
+                />
+              }
+            </td>
+          </tr>
+        </table>
+      </section>
+      <section>
+        <table>
+          <thead>
+            <tr>
+              <td>Denomination operations</td>
+              <td>Current fee</td>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td colSpan={2}>deposit (i)</td>
+            </tr>
+
+            <tr>
+              <td>* 10</td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>* 5</td>
+              <td>0.05</td>
+            </tr>
+            <tr>
+              <td>* 1</td>
+              <td>0.01</td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+      <section>
+        <table>
+          <thead>
+            <tr>
+              <td>Wallet operations</td>
+              <td>Current fee</td>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td>history(i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>kyc (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>account (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>purse (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>wire SEPA (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>closing SEPA(i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>wad SEPA (i) </td>
+              <td>0.1</td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+      <section>
+        <ButtonGroup>
+          <LinkPrimary>Privacy policy</LinkPrimary>
+          <LinkPrimary>Terms of service</LinkPrimary>
+        </ButtonGroup>
+      </section>
+    </Container>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index 6a500a48..5c01b113 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
@@ -57,7 +57,7 @@ export const WithOneExchange = createExample(TestedComponent, 
{
         contentType: "text/plain",
       },
       paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"],
-    },
+    } as any, //TODO: complete with auditors, wireInfo and denominations
   ],
 });
 
@@ -87,7 +87,7 @@ export const WithExchangeInDifferentState = 
createExample(TestedComponent, {
         contentType: "text/plain",
       },
       paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"],
-    },
+    } as any, //TODO: complete with auditors, wireInfo and denominations
     {
       currency: "USD",
       exchangeBaseUrl: "http://exchange3.taler";,
diff --git a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
index 25537691..11f1fb42 100644
--- a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
@@ -36,6 +36,7 @@ import * as a15 from "./AddNewActionView.stories.js";
 import * as a16 from "./DeveloperPage.stories.js";
 import * as a17 from "./QrReader.stories.js";
 import * as a18 from "./DestinationSelection.stories.js";
+import * as a19 from "./ExchangeSelection.stories.js";
 
 export default [
   a1,
@@ -55,4 +56,5 @@ export default [
   a16,
   a17,
   a18,
+  a19,
 ];

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