gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 02/02: wallet-core: restructure denomination record


From: gnunet
Subject: [taler-wallet-core] 02/02: wallet-core: restructure denomination record for easier querying
Date: Wed, 14 Sep 2022 21:27:09 +0200

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

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

commit a66b636dee2ed531bb5119feced80d6569d99176
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Sep 14 21:27:03 2022 +0200

    wallet-core: restructure denomination record for easier querying
---
 .../src/crypto/cryptoImplementation.ts             |  15 +-
 packages/taler-wallet-core/src/db.ts               |  96 ++++---
 packages/taler-wallet-core/src/dbless.ts           |  28 +-
 .../src/operations/backup/export.ts                |  11 +-
 .../src/operations/backup/import.ts                |  45 +++-
 .../taler-wallet-core/src/operations/deposits.ts   |   6 +-
 .../taler-wallet-core/src/operations/exchanges.ts  |  15 +-
 packages/taler-wallet-core/src/operations/pay.ts   |  23 +-
 .../taler-wallet-core/src/operations/refresh.ts    |   6 +-
 .../taler-wallet-core/src/operations/refund.ts     |  23 +-
 packages/taler-wallet-core/src/operations/tip.ts   |   2 +-
 .../src/operations/withdraw.test.ts                | 288 ++++++++++-----------
 .../taler-wallet-core/src/operations/withdraw.ts   |  30 ++-
 packages/taler-wallet-core/src/wallet.ts           |  49 +++-
 14 files changed, 390 insertions(+), 247 deletions(-)

diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index 4ec24a98..9eaf1d91 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -892,17 +892,22 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
     req: DenominationValidationRequest,
   ): Promise<ValidationResult> {
     const { masterPub, denom } = req;
+    const value: AmountJson = {
+      currency: denom.currency,
+      fraction: denom.amountFrac,
+      value: denom.amountVal,
+    };
     const p = 
buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
       .put(decodeCrock(masterPub))
       .put(timestampRoundedToBuffer(denom.stampStart))
       .put(timestampRoundedToBuffer(denom.stampExpireWithdraw))
       .put(timestampRoundedToBuffer(denom.stampExpireDeposit))
       .put(timestampRoundedToBuffer(denom.stampExpireLegal))
-      .put(amountToBuffer(denom.value))
-      .put(amountToBuffer(denom.feeWithdraw))
-      .put(amountToBuffer(denom.feeDeposit))
-      .put(amountToBuffer(denom.feeRefresh))
-      .put(amountToBuffer(denom.feeRefund))
+      .put(amountToBuffer(value))
+      .put(amountToBuffer(denom.fees.feeWithdraw))
+      .put(amountToBuffer(denom.fees.feeDeposit))
+      .put(amountToBuffer(denom.fees.feeRefresh))
+      .put(amountToBuffer(denom.fees.feeRefund))
       .put(decodeCrock(denom.denomPubHash))
       .build();
     const sig = decodeCrock(denom.masterSig);
diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 6dfa63c0..2c4d5582 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -29,7 +29,6 @@ import {
   CoinDepositPermission,
   ContractTerms,
   DenominationPubKey,
-  Duration,
   ExchangeSignKeyJson,
   InternationalizedString,
   MerchantInfo,
@@ -48,6 +47,7 @@ import {
 } from "@gnu-taler/taler-util";
 import { RetryInfo } from "./util/retries.js";
 import { Event, IDBDatabase } from "@gnu-taler/idb-bridge";
+import { DenomInfo } from "./internal-wallet-state.js";
 
 /**
  * Name of the Taler database.  This is effectively the major
@@ -213,26 +213,7 @@ export enum DenominationVerificationStatus {
   VerifiedBad = "verified-bad",
 }
 
-/**
- * Denomination record as stored in the wallet's database.
- */
-export interface DenominationRecord {
-  /**
-   * Value of one coin of the denomination.
-   */
-  value: AmountJson;
-
-  /**
-   * The denomination public key.
-   */
-  denomPub: DenominationPubKey;
-
-  /**
-   * Hash of the denomination public key.
-   * Stored in the database for faster lookups.
-   */
-  denomPubHash: string;
-
+export interface DenomFees {
   /**
    * Fee for withdrawing.
    */
@@ -252,6 +233,30 @@ export interface DenominationRecord {
    * Fee for refunding.
    */
   feeRefund: AmountJson;
+}
+
+/**
+ * Denomination record as stored in the wallet's database.
+ */
+export interface DenominationRecord {
+  currency: string;
+
+  amountVal: number;
+
+  amountFrac: number;
+
+  /**
+   * The denomination public key.
+   */
+  denomPub: DenominationPubKey;
+
+  /**
+   * Hash of the denomination public key.
+   * Stored in the database for faster lookups.
+   */
+  denomPubHash: string;
+
+  fees: DenomFees;
 
   /**
    * Validity start date of the denomination.
@@ -321,6 +326,32 @@ export interface DenominationRecord {
   freshCoinCount?: number;
 }
 
+export namespace DenominationRecord {
+  export function getValue(d: DenominationRecord): AmountJson {
+    return {
+      currency: d.currency,
+      fraction: d.amountFrac,
+      value: d.amountVal,
+    };
+  }
+
+  export function toDenomInfo(d: DenominationRecord): DenomInfo {
+    return {
+      denomPub: d.denomPub,
+      denomPubHash: d.denomPubHash,
+      feeDeposit: d.fees.feeDeposit,
+      feeRefresh: d.fees.feeRefresh,
+      feeRefund: d.fees.feeRefund,
+      feeWithdraw: d.fees.feeWithdraw,
+      stampExpireDeposit: d.stampExpireDeposit,
+      stampExpireLegal: d.stampExpireLegal,
+      stampExpireWithdraw: d.stampExpireWithdraw,
+      stampStart: d.stampStart,
+      value: DenominationRecord.getValue(d),
+    };
+  }
+}
+
 /**
  * Information about one of the exchange's bank accounts.
  */
@@ -2031,7 +2062,10 @@ export interface DatabaseDump {
   version: string;
 }
 
-async function recoverFromDump(db: IDBDatabase, dump: DatabaseDump): 
Promise<void> {
+async function recoverFromDump(
+  db: IDBDatabase,
+  dump: DatabaseDump,
+): Promise<void> {
   return new Promise((resolve, reject) => {
     const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite");
     tx.addEventListener("complete", () => {
@@ -2048,13 +2082,13 @@ async function recoverFromDump(db: IDBDatabase, dump: 
DatabaseDump): Promise<voi
       });
     }
     tx.commit();
-  })
+  });
 }
 
 export async function importDb(db: IDBDatabase, object: any): Promise<void> {
   if ("name" in object && "stores" in object && "version" in object) {
     // looks like a database dump
-    const dump = object as DatabaseDump
+    const dump = object as DatabaseDump;
     return recoverFromDump(db, dump);
   }
 
@@ -2064,10 +2098,12 @@ export async function importDb(db: IDBDatabase, object: 
any): Promise<void> {
 
     if (TALER_META_DB_NAME in someDatabase) {
       //looks like a taler database
-      const currentMainDbValue = 
someDatabase[TALER_META_DB_NAME].objectStores.metaConfig.records[0].value.value
+      const currentMainDbValue =
+        someDatabase[TALER_META_DB_NAME].objectStores.metaConfig.records[0]
+          .value.value;
 
       if (currentMainDbValue !== TALER_DB_NAME) {
-        console.log("not the current database version")
+        console.log("not the current database version");
       }
 
       const talerDb = someDatabase[currentMainDbValue];
@@ -2078,17 +2114,17 @@ export async function importDb(db: IDBDatabase, object: 
any): Promise<void> {
         name: talerDb.schema.databaseName,
         version: talerDb.schema.databaseVersion,
         stores: {},
-      }
+      };
 
       for (let i = 0; i < objectStoreNames.length; i++) {
         const name = objectStoreNames[i];
         const storeDump = {} as { [s: string]: any };
         dump.stores[name] = storeDump;
         talerDb.objectStores[name].records.map((r: any) => {
-          const pkey = r.primaryKey
-          const key = typeof pkey === "string" ? pkey : pkey.join(",")
+          const pkey = r.primaryKey;
+          const key = typeof pkey === "string" ? pkey : pkey.join(",");
           storeDump[key] = r.value;
-        })
+        });
       }
 
       return recoverFromDump(db, dump);
diff --git a/packages/taler-wallet-core/src/dbless.ts 
b/packages/taler-wallet-core/src/dbless.ts
index 3a775c3f..652ba8f5 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -48,6 +48,7 @@ import {
   UnblindedSignature,
   BankWithdrawDetails,
   parseWithdrawUri,
+  AmountJson,
 } from "@gnu-taler/taler-util";
 import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
 import { DenominationRecord } from "./db.js";
@@ -158,11 +159,15 @@ export async function withdrawCoin(args: {
   const planchet = await cryptoApi.createPlanchet({
     coinIndex: 0,
     denomPub: denom.denomPub,
-    feeWithdraw: denom.feeWithdraw,
+    feeWithdraw: denom.fees.feeWithdraw,
     reservePriv: reserveKeyPair.reservePriv,
     reservePub: reserveKeyPair.reservePub,
     secretSeed: encodeCrock(getRandomBytes(32)),
-    value: denom.value,
+    value: {
+      currency: denom.currency,
+      fraction: denom.amountFrac,
+      value: denom.amountVal,
+    },
   });
 
   const reqBody: ExchangeWithdrawRequest = {
@@ -192,8 +197,8 @@ export async function withdrawCoin(args: {
     denomSig: ubSig,
     denomPub: denom.denomPub,
     denomPubHash: denom.denomPubHash,
-    feeDeposit: Amounts.stringify(denom.feeDeposit),
-    feeRefresh: Amounts.stringify(denom.feeRefresh),
+    feeDeposit: Amounts.stringify(denom.fees.feeDeposit),
+    feeRefresh: Amounts.stringify(denom.fees.feeRefresh),
     exchangeBaseUrl: args.exchangeBaseUrl,
   };
 }
@@ -203,7 +208,12 @@ export function findDenomOrThrow(
   amount: AmountString,
 ): DenominationRecord {
   for (const d of exchangeInfo.keys.currentDenominations) {
-    if (Amounts.cmp(d.value, amount) === 0 && isWithdrawableDenom(d)) {
+    const value: AmountJson = {
+      currency: d.currency,
+      fraction: d.amountFrac,
+      value: d.amountVal,
+    };
+    if (Amounts.cmp(value, amount) === 0 && isWithdrawableDenom(d)) {
       return d;
     }
   }
@@ -281,8 +291,12 @@ export async function refreshCoin(req: {
       count: 1,
       denomPub: x.denomPub,
       denomPubHash: x.denomPubHash,
-      feeWithdraw: x.feeWithdraw,
-      value: x.value,
+      feeWithdraw: x.fees.feeWithdraw,
+      value: {
+        currency: x.currency,
+        fraction: x.amountFrac,
+        value: x.amountVal,
+      },
     })),
   });
 
diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts 
b/packages/taler-wallet-core/src/operations/backup/export.ts
index fb1fbf90..35d5e6ef 100644
--- a/packages/taler-wallet-core/src/operations/backup/export.ts
+++ b/packages/taler-wallet-core/src/operations/backup/export.ts
@@ -62,6 +62,7 @@ import {
   AbortStatus,
   CoinSourceType,
   CoinStatus,
+  DenominationRecord,
   ProposalStatus,
   RefreshCoinStatus,
   RefundState,
@@ -221,10 +222,10 @@ export async function exportBackup(
         backupDenoms.push({
           coins: backupCoinsByDenom[denom.denomPubHash] ?? [],
           denom_pub: denom.denomPub,
-          fee_deposit: Amounts.stringify(denom.feeDeposit),
-          fee_refresh: Amounts.stringify(denom.feeRefresh),
-          fee_refund: Amounts.stringify(denom.feeRefund),
-          fee_withdraw: Amounts.stringify(denom.feeWithdraw),
+          fee_deposit: Amounts.stringify(denom.fees.feeDeposit),
+          fee_refresh: Amounts.stringify(denom.fees.feeRefresh),
+          fee_refund: Amounts.stringify(denom.fees.feeRefund),
+          fee_withdraw: Amounts.stringify(denom.fees.feeWithdraw),
           is_offered: denom.isOffered,
           is_revoked: denom.isRevoked,
           master_sig: denom.masterSig,
@@ -232,7 +233,7 @@ export async function exportBackup(
           stamp_expire_legal: denom.stampExpireLegal,
           stamp_expire_withdraw: denom.stampExpireWithdraw,
           stamp_start: denom.stampStart,
-          value: Amounts.stringify(denom.value),
+          value: Amounts.stringify(DenominationRecord.getValue(denom)),
           list_issue_date: denom.listIssueDate,
         });
       });
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts 
b/packages/taler-wallet-core/src/operations/backup/import.ts
index 53e45918..53dc50f3 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -38,6 +38,7 @@ import {
   CoinSource,
   CoinSourceType,
   CoinStatus,
+  DenominationRecord,
   DenominationVerificationStatus,
   DenomSelectionState,
   OperationStatus,
@@ -108,7 +109,10 @@ async function recoverPayCoinSelection(
       coinRecord.denomPubHash,
     ]);
     checkBackupInvariant(!!denom);
-    totalDepositFees = Amounts.add(totalDepositFees, denom.feeDeposit).amount;
+    totalDepositFees = Amounts.add(
+      totalDepositFees,
+      denom.fees.feeDeposit,
+    ).amount;
 
     if (!coveredExchanges.has(coinRecord.exchangeBaseUrl)) {
       const exchangeDetails = await getExchangeDetails(
@@ -175,16 +179,19 @@ async function getDenomSelStateFromBackup(
     denomPubHash: string;
     count: number;
   }[] = [];
-  let totalCoinValue = Amounts.getZero(d0.value.currency);
-  let totalWithdrawCost = Amounts.getZero(d0.value.currency);
+  let totalCoinValue = Amounts.getZero(d0.currency);
+  let totalWithdrawCost = Amounts.getZero(d0.currency);
   for (const s of sel) {
     const d = await tx.denominations.get([exchangeBaseUrl, s.denom_pub_hash]);
     checkBackupInvariant(!!d);
-    totalCoinValue = Amounts.add(totalCoinValue, d.value).amount;
+    totalCoinValue = Amounts.add(
+      totalCoinValue,
+      DenominationRecord.getValue(d),
+    ).amount;
     totalWithdrawCost = Amounts.add(
       totalWithdrawCost,
-      d.value,
-      d.feeWithdraw,
+      DenominationRecord.getValue(d),
+      d.fees.feeWithdraw,
     ).amount;
   }
   return {
@@ -352,17 +359,25 @@ export async function importBackup(
               `importing backup denomination: ${j2s(backupDenomination)}`,
             );
 
+            const value = Amounts.parseOrThrow(backupDenomination.value);
+
             await tx.denominations.put({
               denomPub: backupDenomination.denom_pub,
               denomPubHash: denomPubHash,
               exchangeBaseUrl: backupExchangeDetails.base_url,
               exchangeMasterPub: backupExchangeDetails.master_public_key,
-              feeDeposit: Amounts.parseOrThrow(backupDenomination.fee_deposit),
-              feeRefresh: Amounts.parseOrThrow(backupDenomination.fee_refresh),
-              feeRefund: Amounts.parseOrThrow(backupDenomination.fee_refund),
-              feeWithdraw: Amounts.parseOrThrow(
-                backupDenomination.fee_withdraw,
-              ),
+              fees: {
+                feeDeposit: Amounts.parseOrThrow(
+                  backupDenomination.fee_deposit,
+                ),
+                feeRefresh: Amounts.parseOrThrow(
+                  backupDenomination.fee_refresh,
+                ),
+                feeRefund: Amounts.parseOrThrow(backupDenomination.fee_refund),
+                feeWithdraw: Amounts.parseOrThrow(
+                  backupDenomination.fee_withdraw,
+                ),
+              },
               isOffered: backupDenomination.is_offered,
               isRevoked: backupDenomination.is_revoked,
               masterSig: backupDenomination.master_sig,
@@ -371,7 +386,9 @@ export async function importBackup(
               stampExpireWithdraw: backupDenomination.stamp_expire_withdraw,
               stampStart: backupDenomination.stamp_start,
               verificationStatus: DenominationVerificationStatus.VerifiedGood,
-              value: Amounts.parseOrThrow(backupDenomination.value),
+              currency: value.currency,
+              amountFrac: value.fraction,
+              amountVal: value.value,
               listIssueDate: backupDenomination.list_issue_date,
             });
           }
@@ -648,7 +665,7 @@ export async function importBackup(
               executionTime: backupRefund.execution_time,
               obtainedTime: backupRefund.obtained_time,
               refundAmount: Amounts.parseOrThrow(backupRefund.refund_amount),
-              refundFee: denom.feeRefund,
+              refundFee: denom.fees.feeRefund,
               rtransactionId: backupRefund.rtransaction_id,
               totalRefreshCostBound: Amounts.parseOrThrow(
                 backupRefund.total_refresh_cost_bound,
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 6d63def5..612de824 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -44,6 +44,7 @@ import {
   URL,
 } from "@gnu-taler/taler-util";
 import {
+  DenominationRecord,
   DepositGroupRecord,
   OperationAttemptResult,
   OperationStatus,
@@ -636,7 +637,10 @@ export async function getTotalFeesForDepositAmount(
         const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
           .iter(coin.exchangeBaseUrl)
           .filter((x) =>
-            Amounts.isSameCurrency(x.value, pcs.coinContributions[i]),
+            Amounts.isSameCurrency(
+              DenominationRecord.getValue(x),
+              pcs.coinContributions[i],
+            ),
           );
         const amountLeft = Amounts.sub(
           denom.value,
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 50497844..ca85ff46 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -81,15 +81,18 @@ function denominationRecordFromKeys(
   let denomPub: DenominationPubKey;
   denomPub = denomIn.denom_pub;
   const denomPubHash = encodeCrock(hashDenomPub(denomPub));
+  const value = Amounts.parseOrThrow(denomIn.value);
   const d: DenominationRecord = {
     denomPub,
     denomPubHash,
     exchangeBaseUrl,
     exchangeMasterPub,
-    feeDeposit: Amounts.parseOrThrow(denomIn.fee_deposit),
-    feeRefresh: Amounts.parseOrThrow(denomIn.fee_refresh),
-    feeRefund: Amounts.parseOrThrow(denomIn.fee_refund),
-    feeWithdraw: Amounts.parseOrThrow(denomIn.fee_withdraw),
+    fees: {
+      feeDeposit: Amounts.parseOrThrow(denomIn.fee_deposit),
+      feeRefresh: Amounts.parseOrThrow(denomIn.fee_refresh),
+      feeRefund: Amounts.parseOrThrow(denomIn.fee_refund),
+      feeWithdraw: Amounts.parseOrThrow(denomIn.fee_withdraw),
+    },
     isOffered: true,
     isRevoked: false,
     masterSig: denomIn.master_sig,
@@ -98,7 +101,9 @@ function denominationRecordFromKeys(
     stampExpireWithdraw: denomIn.stamp_expire_withdraw,
     stampStart: denomIn.stamp_start,
     verificationStatus: DenominationVerificationStatus.Unverified,
-    value: Amounts.parseOrThrow(denomIn.value),
+    amountFrac: value.fraction,
+    amountVal: value.value,
+    currency: value.currency,
     listIssueDate,
   };
   return d;
diff --git a/packages/taler-wallet-core/src/operations/pay.ts 
b/packages/taler-wallet-core/src/operations/pay.ts
index bd7b1f7f..5a0d3cee 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -141,13 +141,20 @@ export async function getTotalPaymentCost(
         const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
           .iter(coin.exchangeBaseUrl)
           .filter((x) =>
-            Amounts.isSameCurrency(x.value, pcs.coinContributions[i]),
+            Amounts.isSameCurrency(
+              DenominationRecord.getValue(x),
+              pcs.coinContributions[i],
+            ),
           );
         const amountLeft = Amounts.sub(
-          denom.value,
+          DenominationRecord.getValue(denom),
           pcs.coinContributions[i],
         ).amount;
-        const refreshCost = getTotalRefreshCost(allDenoms, denom, amountLeft);
+        const refreshCost = getTotalRefreshCost(
+          allDenoms,
+          DenominationRecord.toDenomInfo(denom),
+          amountLeft,
+        );
         costs.push(pcs.coinContributions[i]);
         costs.push(refreshCost);
       }
@@ -303,7 +310,7 @@ export async function getCandidatePayCoins(
           if (!denom) {
             throw Error("db inconsistent");
           }
-          if (denom.value.currency !== currency) {
+          if (denom.currency !== currency) {
             logger.warn(
               `same pubkey for different currencies at exchange 
${exchange.baseUrl}`,
             );
@@ -314,10 +321,10 @@ export async function getCandidatePayCoins(
           }
           candidateCoins.push({
             availableAmount: coin.currentAmount,
-            value: denom.value,
+            value: DenominationRecord.getValue(denom),
             coinPub: coin.coinPub,
             denomPub: denom.denomPub,
-            feeDeposit: denom.feeDeposit,
+            feeDeposit: denom.fees.feeDeposit,
             exchangeBaseUrl: denom.exchangeBaseUrl,
             ageCommitmentProof: coin.ageCommitmentProof,
           });
@@ -949,7 +956,7 @@ async function handleInsufficientFunds(
           coinPub,
           contribution: contrib,
           exchangeBaseUrl: coin.exchangeBaseUrl,
-          feeDeposit: denom.feeDeposit,
+          feeDeposit: denom.fees.feeDeposit,
         });
       }
     });
@@ -1269,7 +1276,7 @@ export async function generateDepositPermissions(
       denomKeyType: denom.denomPub.cipher,
       denomSig: coin.denomSig,
       exchangeBaseUrl: coin.exchangeBaseUrl,
-      feeDeposit: denom.feeDeposit,
+      feeDeposit: denom.fees.feeDeposit,
       merchantPub: contractData.merchantPub,
       refundDeadline: contractData.refundDeadline,
       spendAmount: payCoinSel.coinContributions[i],
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index d1c366cd..2d9ad2c0 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -112,7 +112,11 @@ export function getTotalRefreshCost(
   const resultingAmount = Amounts.add(
     Amounts.getZero(withdrawAmount.currency),
     ...withdrawDenoms.selectedDenoms.map(
-      (d) => Amounts.mult(denomMap[d.denomPubHash].value, d.count).amount,
+      (d) =>
+        Amounts.mult(
+          DenominationRecord.getValue(denomMap[d.denomPubHash]),
+          d.count,
+        ).amount,
     ),
   ).amount;
   const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
diff --git a/packages/taler-wallet-core/src/operations/refund.ts 
b/packages/taler-wallet-core/src/operations/refund.ts
index 5ee0680d..f028dfbf 100644
--- a/packages/taler-wallet-core/src/operations/refund.ts
+++ b/packages/taler-wallet-core/src/operations/refund.ts
@@ -51,6 +51,7 @@ import {
 import {
   AbortStatus,
   CoinStatus,
+  DenominationRecord,
   OperationAttemptResult,
   PurchaseRecord,
   RefundReason,
@@ -148,7 +149,7 @@ async function applySuccessfulRefund(
   }
   refreshCoinsMap[coin.coinPub] = { coinPub: coin.coinPub };
   const refundAmount = Amounts.parseOrThrow(r.refund_amount);
-  const refundFee = denom.feeRefund;
+  const refundFee = denom.fees.feeRefund;
   coin.status = CoinStatus.Dormant;
   coin.currentAmount = Amounts.add(coin.currentAmount, refundAmount).amount;
   coin.currentAmount = Amounts.sub(coin.currentAmount, refundFee).amount;
@@ -162,12 +163,12 @@ async function applySuccessfulRefund(
   const amountLeft = Amounts.sub(
     Amounts.add(coin.currentAmount, Amounts.parseOrThrow(r.refund_amount))
       .amount,
-    denom.feeRefund,
+    denom.fees.feeRefund,
   ).amount;
 
   const totalRefreshCostBound = getTotalRefreshCost(
     allDenoms,
-    denom,
+    DenominationRecord.toDenomInfo(denom),
     amountLeft,
   );
 
@@ -176,7 +177,7 @@ async function applySuccessfulRefund(
     obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
     executionTime: r.execution_time,
     refundAmount: Amounts.parseOrThrow(r.refund_amount),
-    refundFee: denom.feeRefund,
+    refundFee: denom.fees.feeRefund,
     totalRefreshCostBound,
     coinPub: r.coin_pub,
     rtransactionId: r.rtransaction_id,
@@ -214,12 +215,12 @@ async function storePendingRefund(
   const amountLeft = Amounts.sub(
     Amounts.add(coin.currentAmount, Amounts.parseOrThrow(r.refund_amount))
       .amount,
-    denom.feeRefund,
+    denom.fees.feeRefund,
   ).amount;
 
   const totalRefreshCostBound = getTotalRefreshCost(
     allDenoms,
-    denom,
+    DenominationRecord.toDenomInfo(denom),
     amountLeft,
   );
 
@@ -228,7 +229,7 @@ async function storePendingRefund(
     obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
     executionTime: r.execution_time,
     refundAmount: Amounts.parseOrThrow(r.refund_amount),
-    refundFee: denom.feeRefund,
+    refundFee: denom.fees.feeRefund,
     totalRefreshCostBound,
     coinPub: r.coin_pub,
     rtransactionId: r.rtransaction_id,
@@ -267,12 +268,12 @@ async function storeFailedRefund(
   const amountLeft = Amounts.sub(
     Amounts.add(coin.currentAmount, Amounts.parseOrThrow(r.refund_amount))
       .amount,
-    denom.feeRefund,
+    denom.fees.feeRefund,
   ).amount;
 
   const totalRefreshCostBound = getTotalRefreshCost(
     allDenoms,
-    denom,
+    DenominationRecord.toDenomInfo(denom),
     amountLeft,
   );
 
@@ -281,7 +282,7 @@ async function storeFailedRefund(
     obtainedTime: TalerProtocolTimestamp.now(),
     executionTime: r.execution_time,
     refundAmount: Amounts.parseOrThrow(r.refund_amount),
-    refundFee: denom.feeRefund,
+    refundFee: denom.fees.feeRefund,
     totalRefreshCostBound,
     coinPub: r.coin_pub,
     rtransactionId: r.rtransaction_id,
@@ -314,7 +315,7 @@ async function storeFailedRefund(
         coin.currentAmount = Amounts.add(coin.currentAmount, contrib).amount;
         coin.currentAmount = Amounts.sub(
           coin.currentAmount,
-          denom.feeRefund,
+          denom.fees.feeRefund,
         ).amount;
       }
       refreshCoinsMap[coin.coinPub] = { coinPub: coin.coinPub };
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index f70e2d02..c8f327a5 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -306,7 +306,7 @@ export async function processTip(
         coinIndex: i,
         walletTipId: walletTipId,
       },
-      currentAmount: denom.value,
+      currentAmount: DenominationRecord.getValue(denom),
       denomPubHash: denom.denomPubHash,
       denomSig: { cipher: DenomKeyType.Rsa, rsa_signature: denomSigRsa.sig },
       exchangeBaseUrl: tipRecord.exchangeBaseUrl,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts 
b/packages/taler-wallet-core/src/operations/withdraw.test.ts
index 9f914671..70b4f73c 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts
@@ -38,25 +38,27 @@ test("withdrawal selection bug repro", (t) => {
         
"Q21FQSSG4FXNT96Z14CHXM8N1RZAG9GPHAV8PRWS0PZAAVWH7PBW6R97M2CH19KKP65NNSWXY7B6S53PT3CBM342E357ZXDDJ8RDVW8",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -75,11 +77,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 0,
-        value: 1000,
-      },
+      currency: "KUDOS",
+      amountFrac: 0,
+      amountVal: 1000,
       listIssueDate: { t_s: 0 },
     },
     {
@@ -94,25 +94,27 @@ test("withdrawal selection bug repro", (t) => {
         
"447WA23SCBATMABHA0793F92MYTBYVPYMMQHCPKMKVY5P7RZRFMQ6VRW0Y8HRA7177GTBT0TBT08R21DZD129AJ995H9G09XBFE55G8",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -131,11 +133,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 0,
-        value: 10,
-      },
+      amountFrac: 0,
+      amountVal: 10,
+      currency: "KUDOS",
       listIssueDate: { t_s: 0 },
     },
     {
@@ -149,25 +149,27 @@ test("withdrawal selection bug repro", (t) => {
         
"JS61DTKAFM0BX8Q4XV3ZSKB921SM8QK745Z2AFXTKFMBHHFNBD8TQ5ETJHFNDGBGX22FFN2A2ERNYG1SGSDQWNQHQQ2B14DBVJYJG8R",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -186,11 +188,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 0,
-        value: 5,
-      },
+      amountFrac: 0,
+      amountVal: 5,
+      currency: "KUDOS",
       listIssueDate: { t_s: 0 },
     },
     {
@@ -205,25 +205,27 @@ test("withdrawal selection bug repro", (t) => {
         
"8T51NEY81VMPQ180EQ5WR0YH7GMNNT90W55Q0514KZM18AZT71FHJGJHQXGK0WTA7ACN1X2SD0S53XPBQ1A9KH960R48VCVVM6E3TH8",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -242,11 +244,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 0,
-        value: 1,
-      },
+      amountFrac: 0,
+      amountVal: 1,
+      currency: "KUDOS",
       listIssueDate: { t_s: 0 },
     },
     {
@@ -260,25 +260,27 @@ test("withdrawal selection bug repro", (t) => {
         
"A41HW0Q2H9PCNMEWW0C0N45QAYVXZ8SBVRRAHE4W6X24SV1TH38ANTWDT80JXEBW9Z8PVPGT9GFV2EYZWJ5JW5W1N34NFNKHQSZ1PFR",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -297,11 +299,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 10000000,
-        value: 0,
-      },
+      amountFrac: 10000000,
+      amountVal: 0,
+      currency: "KUDOS",
       listIssueDate: { t_s: 0 },
     },
     {
@@ -315,25 +315,27 @@ test("withdrawal selection bug repro", (t) => {
         
"F5NGBX33DTV4595XZZVK0S2MA1VMXFEJQERE5EBP5DS4QQ9EFRANN7YHWC1TKSHT2K6CQWDBRES8D3DWR0KZF5RET40B4AZXZ0RW1ZG",
       exchangeBaseUrl: "https://exchange.demo.taler.net/";,
       exchangeMasterPub: "",
-      feeDeposit: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefresh: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeRefund: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
-      },
-      feeWithdraw: {
-        currency: "KUDOS",
-        fraction: 1000000,
-        value: 0,
+      fees: {
+        feeDeposit: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefresh: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeRefund: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
+        feeWithdraw: {
+          currency: "KUDOS",
+          fraction: 1000000,
+          value: 0,
+        },
       },
       isOffered: true,
       isRevoked: false,
@@ -352,11 +354,9 @@ test("withdrawal selection bug repro", (t) => {
         t_s: 1585229388,
       },
       verificationStatus: DenominationVerificationStatus.Unverified,
-      value: {
-        currency: "KUDOS",
-        fraction: 0,
-        value: 2,
-      },
+      amountFrac: 0,
+      amountVal: 2,
+      currency: "KUDOS",
       listIssueDate: { t_s: 0 },
     },
   ];
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts 
b/packages/taler-wallet-core/src/operations/withdraw.ts
index bee83265..47252a7e 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -243,11 +243,19 @@ export function selectWithdrawalDenominations(
   let totalWithdrawCost = Amounts.getZero(amountAvailable.currency);
 
   denoms = denoms.filter(isWithdrawableDenom);
-  denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+  denoms.sort((d1, d2) =>
+    Amounts.cmp(
+      DenominationRecord.getValue(d2),
+      DenominationRecord.getValue(d1),
+    ),
+  );
 
   for (const d of denoms) {
     let count = 0;
-    const cost = Amounts.add(d.value, d.feeWithdraw).amount;
+    const cost = Amounts.add(
+      DenominationRecord.getValue(d),
+      d.fees.feeWithdraw,
+    ).amount;
     for (;;) {
       if (Amounts.cmp(remaining, cost) < 0) {
         break;
@@ -258,7 +266,7 @@ export function selectWithdrawalDenominations(
     if (count > 0) {
       totalCoinValue = Amounts.add(
         totalCoinValue,
-        Amounts.mult(d.value, count).amount,
+        Amounts.mult(DenominationRecord.getValue(d), count).amount,
       ).amount;
       totalWithdrawCost = Amounts.add(
         totalWithdrawCost,
@@ -306,22 +314,30 @@ export function selectForcedWithdrawalDenominations(
   let totalWithdrawCost = Amounts.getZero(amountAvailable.currency);
 
   denoms = denoms.filter(isWithdrawableDenom);
-  denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
+  denoms.sort((d1, d2) =>
+    Amounts.cmp(
+      DenominationRecord.getValue(d2),
+      DenominationRecord.getValue(d1),
+    ),
+  );
 
   for (const fds of forcedDenomSel.denoms) {
     const count = fds.count;
     const denom = denoms.find((x) => {
-      return Amounts.cmp(x.value, fds.value) == 0;
+      return Amounts.cmp(DenominationRecord.getValue(x), fds.value) == 0;
     });
     if (!denom) {
       throw Error(
         `unable to find denom for forced selection (value ${fds.value})`,
       );
     }
-    const cost = Amounts.add(denom.value, denom.feeWithdraw).amount;
+    const cost = Amounts.add(
+      DenominationRecord.getValue(denom),
+      denom.fees.feeWithdraw,
+    ).amount;
     totalCoinValue = Amounts.add(
       totalCoinValue,
-      Amounts.mult(denom.value, count).amount,
+      Amounts.mult(DenominationRecord.getValue(denom), count).amount,
     ).amount;
     totalWithdrawCost = Amounts.add(
       totalWithdrawCost,
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index afbee4e6..02ed8a61 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -102,6 +102,7 @@ import {
   CoinRecord,
   CoinSourceType,
   CoinStatus,
+  DenominationRecord,
   exportDb,
   importDb,
   OperationAttemptResult,
@@ -731,14 +732,29 @@ async function getExchangeDetailedInfo(
         return;
       }
 
-      const denominations = await tx.denominations.indexes.byExchangeBaseUrl
-        .iter(ex.baseUrl)
-        .toArray();
+      const denominationRecords =
+        await tx.denominations.indexes.byExchangeBaseUrl
+          .iter(ex.baseUrl)
+          .toArray();
 
-      if (!denominations) {
+      if (!denominationRecords) {
         return;
       }
 
+      const denominations: DenomInfo[] = denominationRecords.map((x) => ({
+        denomPub: x.denomPub,
+        denomPubHash: x.denomPubHash,
+        feeDeposit: x.fees.feeDeposit,
+        feeRefresh: x.fees.feeRefresh,
+        feeRefund: x.fees.feeRefund,
+        feeWithdraw: x.fees.feeWithdraw,
+        stampExpireDeposit: x.stampExpireDeposit,
+        stampExpireLegal: x.stampExpireLegal,
+        stampExpireWithdraw: x.stampExpireWithdraw,
+        stampStart: x.stampStart,
+        value: DenominationRecord.getValue(x),
+      }));
+
       return {
         info: {
           exchangeBaseUrl: ex.baseUrl,
@@ -753,7 +769,7 @@ async function getExchangeDetailedInfo(
           auditors: exchangeDetails.auditors,
           wireInfo: exchangeDetails.wireInfo,
         },
-        denominations: denominations,
+        denominations,
       };
     });
 
@@ -969,7 +985,11 @@ async function dumpCoins(ws: InternalWalletState): 
Promise<CoinDumpJson> {
           coin_pub: c.coinPub,
           denom_pub: denomInfo.denomPub,
           denom_pub_hash: c.denomPubHash,
-          denom_value: Amounts.stringify(denom.value),
+          denom_value: Amounts.stringify({
+            value: denom.amountVal,
+            currency: denom.currency,
+            fraction: denom.amountFrac,
+          }),
           exchange_base_url: c.exchangeBaseUrl,
           refresh_parent_coin_pub: refreshParentCoinPub,
           remaining_value: Amounts.stringify(c.currentAmount),
@@ -1566,9 +1586,22 @@ class InternalWalletStateImpl implements 
InternalWalletState {
     }
     const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]);
     if (d) {
-      this.denomCache[key] = d;
+      const denomInfo = {
+        denomPub: d.denomPub,
+        denomPubHash: d.denomPubHash,
+        feeDeposit: d.fees.feeDeposit,
+        feeRefresh: d.fees.feeRefresh,
+        feeRefund: d.fees.feeRefund,
+        feeWithdraw: d.fees.feeWithdraw,
+        stampExpireDeposit: d.stampExpireDeposit,
+        stampExpireLegal: d.stampExpireLegal,
+        stampExpireWithdraw: d.stampExpireWithdraw,
+        stampStart: d.stampStart,
+        value: DenominationRecord.getValue(d),
+      };
+      return denomInfo;
     }
-    return d;
+    return undefined;
   }
 
   notify(n: WalletNotification): void {

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