wallet-core: more DB cleanup

This commit is contained in:
Florian Dold 2023-09-08 13:33:21 +02:00
parent 2ae952cdfa
commit 4898f50db7
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
16 changed files with 78 additions and 183 deletions

View File

@ -527,22 +527,6 @@ export interface OrderShortInfo {
*/ */
summary_i18n?: InternationalizedString; summary_i18n?: InternationalizedString;
/**
* List of products that are part of the order
*/
products: Product[] | undefined;
/**
* Time indicating when the order should be delivered.
* May be overwritten by individual products.
*/
delivery_date?: TalerProtocolTimestamp;
/**
* Delivery location for (all!) products.
*/
delivery_location?: Location;
/** /**
* URL of the fulfillment, given by the merchant * URL of the fulfillment, given by the merchant
*/ */
@ -724,7 +708,6 @@ export const codecForOrderShortInfo = (): Codec<OrderShortInfo> =>
.property("fulfillmentUrl", codecOptional(codecForString())) .property("fulfillmentUrl", codecOptional(codecForString()))
.property("merchant", codecForMerchantInfo()) .property("merchant", codecForMerchantInfo())
.property("orderId", codecForString()) .property("orderId", codecForString())
.property("products", codecOptional(codecForList(codecForProduct())))
.property("summary", codecForString()) .property("summary", codecForString())
.property("summary_i18n", codecOptional(codecForInternationalizedString())) .property("summary_i18n", codecOptional(codecForInternationalizedString()))
.build("OrderShortInfo"); .build("OrderShortInfo");

View File

@ -959,11 +959,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
req: DenominationValidationRequest, req: DenominationValidationRequest,
): Promise<ValidationResult> { ): Promise<ValidationResult> {
const { masterPub, denom } = req; const { masterPub, denom } = req;
const value: AmountJson = { const value: AmountJson = Amounts.parseOrThrow(denom.value);
currency: denom.currency,
fraction: denom.amountFrac,
value: denom.amountVal,
};
const p = buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY) const p = buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
.put(decodeCrock(masterPub)) .put(decodeCrock(masterPub))
.put(timestampRoundedToBuffer(denom.stampStart)) .put(timestampRoundedToBuffer(denom.stampStart))

View File

@ -28,56 +28,53 @@ import {
} from "@gnu-taler/idb-bridge"; } from "@gnu-taler/idb-bridge";
import { import {
AgeCommitmentProof, AgeCommitmentProof,
AmountJson,
AmountString, AmountString,
Amounts,
AttentionInfo,
Codec,
CoinEnvelope, CoinEnvelope,
CoinPublicKeyString,
CoinRefreshRequest, CoinRefreshRequest,
CoinStatus, CoinStatus,
MerchantContractTerms, DenomSelectionState,
DenominationInfo, DenominationInfo,
DenominationPubKey, DenominationPubKey,
DenomSelectionState,
EddsaPublicKeyString, EddsaPublicKeyString,
EddsaSignatureString, EddsaSignatureString,
ExchangeAuditor, ExchangeAuditor,
ExchangeGlobalFees, ExchangeGlobalFees,
HashCodeString,
InternationalizedString, InternationalizedString,
Location, Logger,
MerchantContractTerms,
MerchantInfo, MerchantInfo,
PayCoinSelection, PayCoinSelection,
PeerContractTerms, PeerContractTerms,
Product,
RefreshReason, RefreshReason,
TalerErrorDetail, TalerErrorDetail,
TalerPreciseTimestamp,
TalerProtocolDuration, TalerProtocolDuration,
TalerProtocolTimestamp, TalerProtocolTimestamp,
TransactionIdStr, TransactionIdStr,
UnblindedSignature, UnblindedSignature,
WireInfo, WireInfo,
HashCodeString,
Amounts,
AttentionInfo,
Logger,
CoinPublicKeyString,
TalerPreciseTimestamp,
codecForAny, codecForAny,
Codec,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { RetryInfo, TaskIdentifiers } from "./operations/common.js";
import { import {
DbAccess, DbAccess,
DbReadOnlyTransaction, DbReadOnlyTransaction,
DbReadWriteTransaction, DbReadWriteTransaction,
describeContents,
describeIndex,
describeStore,
GetReadWriteAccess, GetReadWriteAccess,
IndexDescriptor, IndexDescriptor,
openDatabase,
StoreDescriptor, StoreDescriptor,
StoreNames, StoreNames,
StoreWithIndexes, StoreWithIndexes,
describeContents,
describeIndex,
describeStore,
openDatabase,
} from "./util/query.js"; } from "./util/query.js";
import { RetryInfo, TaskIdentifiers } from "./operations/common.js";
/** /**
* This file contains the database schema of the Taler wallet together * This file contains the database schema of the Taler wallet together
@ -109,6 +106,9 @@ import { RetryInfo, TaskIdentifiers } from "./operations/common.js";
store. store.
- More object stores should have an "id" primary key, - More object stores should have an "id" primary key,
as this makes referencing less expensive. as this makes referencing less expensive.
- Coin selections should probably go into a separate object store.
- Some records should be split up into an extra "details" record
that we don't always need to iterate over.
*/ */
/** /**
@ -323,12 +323,14 @@ export interface DenomFees {
* Denomination record as stored in the wallet's database. * Denomination record as stored in the wallet's database.
*/ */
export interface DenominationRecord { export interface DenominationRecord {
/**
* Currency of the denomination.
*
* Stored separately as we have an index on it.
*/
currency: string; currency: string;
// FIXME: Use binary encoding of amount instead? value: AmountString;
amountVal: number;
amountFrac: number;
/** /**
* The denomination public key. * The denomination public key.
@ -407,14 +409,6 @@ export interface DenominationRecord {
} }
export namespace DenominationRecord { export namespace DenominationRecord {
export function getValue(d: DenominationRecord): AmountJson {
return {
currency: d.currency,
fraction: d.amountFrac,
value: d.amountVal,
};
}
export function toDenomInfo(d: DenominationRecord): DenominationInfo { export function toDenomInfo(d: DenominationRecord): DenominationInfo {
return { return {
denomPub: d.denomPub, denomPub: d.denomPub,
@ -427,7 +421,7 @@ export namespace DenominationRecord {
stampExpireLegal: d.stampExpireLegal, stampExpireLegal: d.stampExpireLegal,
stampExpireWithdraw: d.stampExpireWithdraw, stampExpireWithdraw: d.stampExpireWithdraw,
stampStart: d.stampStart, stampStart: d.stampStart,
value: Amounts.stringify(DenominationRecord.getValue(d)), value: Amounts.stringify(d.value),
exchangeBaseUrl: d.exchangeBaseUrl, exchangeBaseUrl: d.exchangeBaseUrl,
}; };
} }
@ -1056,9 +1050,6 @@ export interface AllowedExchangeInfo {
* processing in the wallet. * processing in the wallet.
*/ */
export interface WalletContractData { export interface WalletContractData {
products?: Product[];
summaryI18n: { [lang_tag: string]: string } | undefined;
/** /**
* Fulfillment URL, or the empty string if the order has no fulfillment URL. * Fulfillment URL, or the empty string if the order has no fulfillment URL.
* *
@ -1076,6 +1067,7 @@ export interface WalletContractData {
orderId: string; orderId: string;
merchantBaseUrl: string; merchantBaseUrl: string;
summary: string; summary: string;
summaryI18n: { [lang_tag: string]: string } | undefined;
autoRefund: TalerProtocolDuration | undefined; autoRefund: TalerProtocolDuration | undefined;
maxWireFee: AmountString; maxWireFee: AmountString;
wireFeeAmortization: number; wireFeeAmortization: number;
@ -1087,8 +1079,6 @@ export interface WalletContractData {
wireInfoHash: string; wireInfoHash: string;
maxDepositFee: AmountString; maxDepositFee: AmountString;
minimumAge?: number; minimumAge?: number;
deliveryDate: TalerProtocolTimestamp | undefined;
deliveryLocation: Location | undefined;
} }
export enum PurchaseStatus { export enum PurchaseStatus {
@ -2095,8 +2085,7 @@ export interface OperationRetryRecord {
*/ */
export interface CoinAvailabilityRecord { export interface CoinAvailabilityRecord {
currency: string; currency: string;
amountVal: number; value: AmountString;
amountFrac: number;
denomPubHash: string; denomPubHash: string;
exchangeBaseUrl: string; exchangeBaseUrl: string;

View File

@ -159,11 +159,7 @@ export async function withdrawCoin(args: {
reservePriv: reserveKeyPair.reservePriv, reservePriv: reserveKeyPair.reservePriv,
reservePub: reserveKeyPair.reservePub, reservePub: reserveKeyPair.reservePub,
secretSeed: encodeCrock(getRandomBytes(32)), secretSeed: encodeCrock(getRandomBytes(32)),
value: { value: Amounts.parseOrThrow(denom.value),
currency: denom.currency,
fraction: denom.amountFrac,
value: denom.amountVal,
},
}); });
const reqBody: ExchangeWithdrawRequest = { const reqBody: ExchangeWithdrawRequest = {
@ -211,11 +207,7 @@ export function findDenomOrThrow(
): DenominationRecord { ): DenominationRecord {
const denomselAllowLate = options.denomselAllowLate ?? false; const denomselAllowLate = options.denomselAllowLate ?? false;
for (const d of exchangeInfo.keys.currentDenominations) { for (const d of exchangeInfo.keys.currentDenominations) {
const value: AmountJson = { const value: AmountJson = Amounts.parseOrThrow(d.value);
currency: d.currency,
fraction: d.amountFrac,
value: d.amountVal,
};
if ( if (
Amounts.cmp(value, amount) === 0 && Amounts.cmp(value, amount) === 0 &&
isWithdrawableDenom(d, denomselAllowLate) isWithdrawableDenom(d, denomselAllowLate)
@ -303,11 +295,7 @@ export async function refreshCoin(req: {
denomPub: x.denomPub, denomPub: x.denomPub,
denomPubHash: x.denomPubHash, denomPubHash: x.denomPubHash,
feeWithdraw: x.fees.feeWithdraw, feeWithdraw: x.fees.feeWithdraw,
value: Amounts.stringify({ value: x.value,
currency: x.currency,
fraction: x.amountFrac,
value: x.amountVal,
}),
})), })),
meltCoinMaxAge: oldCoin.maxAge, meltCoinMaxAge: oldCoin.maxAge,
}); });

View File

@ -133,11 +133,7 @@ export async function getBalancesInsideTransaction(
const b = initBalance(ca.currency); const b = initBalance(ca.currency);
const count = ca.visibleCoinCount ?? 0; const count = ca.visibleCoinCount ?? 0;
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
b.available = Amounts.add(b.available, { b.available = Amounts.add(b.available, ca.value).amount;
currency: ca.currency,
fraction: ca.amountFrac,
value: ca.amountVal,
}).amount;
} }
}); });
@ -408,11 +404,7 @@ export async function getMerchantPaymentBalanceDetails(
if (ca.currency != req.currency) { if (ca.currency != req.currency) {
return; return;
} }
const singleCoinAmount: AmountJson = { const singleCoinAmount: AmountJson = Amounts.parseOrThrow(ca.value);
currency: ca.currency,
fraction: ca.amountFrac,
value: ca.amountVal,
};
const coinAmount: AmountJson = Amounts.mult( const coinAmount: AmountJson = Amounts.mult(
singleCoinAmount, singleCoinAmount,
ca.freshCoinCount, ca.freshCoinCount,
@ -530,11 +522,7 @@ export async function getPeerPaymentBalanceDetailsInTx(
) { ) {
return; return;
} }
const singleCoinAmount: AmountJson = { const singleCoinAmount: AmountJson = Amounts.parseOrThrow(ca.value);
currency: ca.currency,
fraction: ca.amountFrac,
value: ca.amountVal,
};
const coinAmount: AmountJson = Amounts.mult( const coinAmount: AmountJson = Amounts.mult(
singleCoinAmount, singleCoinAmount,
ca.freshCoinCount, ca.freshCoinCount,

View File

@ -26,7 +26,6 @@ import {
CoinRefreshRequest, CoinRefreshRequest,
CoinStatus, CoinStatus,
Duration, Duration,
ErrorInfoSummary,
ExchangeEntryStatus, ExchangeEntryStatus,
ExchangeListItem, ExchangeListItem,
ExchangeTosStatus, ExchangeTosStatus,
@ -34,9 +33,11 @@ import {
getErrorDetailFromException, getErrorDetailFromException,
j2s, j2s,
Logger, Logger,
makeErrorDetail,
NotificationType, NotificationType,
OperationErrorInfo, OperationErrorInfo,
RefreshReason, RefreshReason,
TalerError,
TalerErrorCode, TalerErrorCode,
TalerErrorDetail, TalerErrorDetail,
TombstoneIdStr, TombstoneIdStr,
@ -44,32 +45,31 @@ import {
TransactionType, TransactionType,
WalletNotification, WalletNotification,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { CryptoApiStoppedError } from "../crypto/workers/crypto-dispatcher.js";
import { import {
WalletStoresV1,
CoinRecord,
ExchangeDetailsRecord,
ExchangeEntryRecord,
BackupProviderRecord, BackupProviderRecord,
CoinRecord,
DepositGroupRecord, DepositGroupRecord,
PeerPullPaymentIncomingRecord, ExchangeDetailsRecord,
ExchangeEntryDbRecordStatus,
ExchangeEntryDbUpdateStatus,
ExchangeEntryRecord,
PeerPullCreditRecord, PeerPullCreditRecord,
PeerPushPaymentIncomingRecord, PeerPullPaymentIncomingRecord,
PeerPushDebitRecord, PeerPushDebitRecord,
PeerPushPaymentIncomingRecord,
PurchaseRecord, PurchaseRecord,
RecoupGroupRecord, RecoupGroupRecord,
RefreshGroupRecord, RefreshGroupRecord,
RewardRecord, RewardRecord,
WalletStoresV1,
WithdrawalGroupRecord, WithdrawalGroupRecord,
ExchangeEntryDbUpdateStatus,
ExchangeEntryDbRecordStatus,
} from "../db.js"; } from "../db.js";
import { makeErrorDetail, TalerError } from "@gnu-taler/taler-util";
import { InternalWalletState } from "../internal-wallet-state.js"; import { InternalWalletState } from "../internal-wallet-state.js";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js";
import { CryptoApiStoppedError } from "../crypto/workers/crypto-dispatcher.js";
import { PendingTaskType, TaskId } from "../pending-types.js"; import { PendingTaskType, TaskId } from "../pending-types.js";
import { assertUnreachable } from "../util/assertUnreachable.js"; import { assertUnreachable } from "../util/assertUnreachable.js";
import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js";
import { constructTransactionIdentifier } from "./transactions.js"; import { constructTransactionIdentifier } from "./transactions.js";
const logger = new Logger("operations/common.ts"); const logger = new Logger("operations/common.ts");
@ -144,8 +144,7 @@ export async function makeCoinAvailable(
if (!car) { if (!car) {
car = { car = {
maxAge: ageRestriction, maxAge: ageRestriction,
amountFrac: denom.amountFrac, value: denom.value,
amountVal: denom.amountVal,
currency: denom.currency, currency: denom.currency,
denomPubHash: denom.denomPubHash, denomPubHash: denom.denomPubHash,
exchangeBaseUrl: denom.exchangeBaseUrl, exchangeBaseUrl: denom.exchangeBaseUrl,

View File

@ -1539,7 +1539,7 @@ async function getTotalFeesForDepositAmount(
.iter(coin.exchangeBaseUrl) .iter(coin.exchangeBaseUrl)
.filter((x) => .filter((x) =>
Amounts.isSameCurrency( Amounts.isSameCurrency(
DenominationRecord.getValue(x), x.value,
pcs.coinContributions[i], pcs.coinContributions[i],
), ),
); );

View File

@ -443,8 +443,7 @@ async function downloadExchangeKeysInfo(
exchangeMasterPub: exchangeKeysJsonUnchecked.master_public_key, exchangeMasterPub: exchangeKeysJsonUnchecked.master_public_key,
isOffered: true, isOffered: true,
isRevoked: false, isRevoked: false,
amountFrac: value.fraction, value: Amounts.stringify(value),
amountVal: value.value,
currency: value.currency, currency: value.currency,
stampExpireDeposit: denomIn.stamp_expire_deposit, stampExpireDeposit: denomIn.stamp_expire_deposit,
stampExpireLegal: denomIn.stamp_expire_legal, stampExpireLegal: denomIn.stamp_expire_legal,

View File

@ -174,12 +174,12 @@ export async function getTotalPaymentCost(
.iter(coin.exchangeBaseUrl) .iter(coin.exchangeBaseUrl)
.filter((x) => .filter((x) =>
Amounts.isSameCurrency( Amounts.isSameCurrency(
DenominationRecord.getValue(x), x.value,
pcs.coinContributions[i], pcs.coinContributions[i],
), ),
); );
const amountLeft = Amounts.sub( const amountLeft = Amounts.sub(
DenominationRecord.getValue(denom), denom.value,
pcs.coinContributions[i], pcs.coinContributions[i],
).amount; ).amount;
const refreshCost = getTotalRefreshCost( const refreshCost = getTotalRefreshCost(

View File

@ -108,16 +108,8 @@ export async function getTotalPeerPaymentCost(
} }
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
.iter(coin.exchangeBaseUrl) .iter(coin.exchangeBaseUrl)
.filter((x) => .filter((x) => Amounts.isSameCurrency(x.value, pcs[i].contribution));
Amounts.isSameCurrency( const amountLeft = Amounts.sub(denom.value, pcs[i].contribution).amount;
DenominationRecord.getValue(x),
pcs[i].contribution,
),
);
const amountLeft = Amounts.sub(
DenominationRecord.getValue(denom),
pcs[i].contribution,
).amount;
const refreshCost = getTotalRefreshCost( const refreshCost = getTotalRefreshCost(
allDenoms, allDenoms,
DenominationRecord.toDenomInfo(denom), DenominationRecord.toDenomInfo(denom),

View File

@ -134,11 +134,7 @@ export function getTotalRefreshCost(
const resultingAmount = Amounts.add( const resultingAmount = Amounts.add(
Amounts.zeroOfCurrency(withdrawAmount.currency), Amounts.zeroOfCurrency(withdrawAmount.currency),
...withdrawDenoms.selectedDenoms.map( ...withdrawDenoms.selectedDenoms.map(
(d) => (d) => Amounts.mult(denomMap[d.denomPubHash].value, d.count).amount,
Amounts.mult(
DenominationRecord.getValue(denomMap[d.denomPubHash]),
d.count,
).amount,
), ),
).amount; ).amount;
const totalCost = Amounts.sub(amountLeft, resultingAmount).amount; const totalCost = Amounts.sub(amountLeft, resultingAmount).amount;
@ -1200,11 +1196,7 @@ export async function autoRefresh(
if (AbsoluteTime.isExpired(executeThreshold)) { if (AbsoluteTime.isExpired(executeThreshold)) {
refreshCoins.push({ refreshCoins.push({
coinPub: coin.coinPub, coinPub: coin.coinPub,
amount: Amounts.stringify({ amount: denom.value,
value: denom.amountVal,
fraction: denom.amountFrac,
currency: denom.currency,
}),
}); });
} else { } else {
const checkThreshold = getAutoRefreshCheckThreshold(denom); const checkThreshold = getAutoRefreshCheckThreshold(denom);

View File

@ -884,7 +884,6 @@ async function buildTransactionForPurchase(
const info: OrderShortInfo = { const info: OrderShortInfo = {
merchant: contractData.merchant, merchant: contractData.merchant,
orderId: contractData.orderId, orderId: contractData.orderId,
products: contractData.products,
summary: contractData.summary, summary: contractData.summary,
summary_i18n: contractData.summaryI18n, summary_i18n: contractData.summaryI18n,
contractTermsHash: contractData.contractTermsHash, contractTermsHash: contractData.contractTermsHash,

View File

@ -78,8 +78,7 @@ test("withdrawal selection bug repro", (t) => {
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
currency: "KUDOS", currency: "KUDOS",
amountFrac: 0, value: "KUDOS:1000",
amountVal: 1000,
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },
{ {
@ -133,8 +132,7 @@ test("withdrawal selection bug repro", (t) => {
t_s: 1585229388, t_s: 1585229388,
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
amountFrac: 0, value: "KUDOS:10",
amountVal: 10,
currency: "KUDOS", currency: "KUDOS",
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },
@ -188,8 +186,7 @@ test("withdrawal selection bug repro", (t) => {
t_s: 1585229388, t_s: 1585229388,
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
amountFrac: 0, value: "KUDOS:5",
amountVal: 5,
currency: "KUDOS", currency: "KUDOS",
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },
@ -244,8 +241,7 @@ test("withdrawal selection bug repro", (t) => {
t_s: 1585229388, t_s: 1585229388,
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
amountFrac: 0, value: "KUDOS:1",
amountVal: 1,
currency: "KUDOS", currency: "KUDOS",
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },
@ -299,8 +295,11 @@ test("withdrawal selection bug repro", (t) => {
t_s: 1585229388, t_s: 1585229388,
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
amountFrac: 10000000, value: Amounts.stringify({
amountVal: 0, currency: "KUDOS",
fraction: 10000000,
value: 0,
}),
currency: "KUDOS", currency: "KUDOS",
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },
@ -354,8 +353,7 @@ test("withdrawal selection bug repro", (t) => {
t_s: 1585229388, t_s: 1585229388,
}, },
verificationStatus: DenominationVerificationStatus.Unverified, verificationStatus: DenominationVerificationStatus.Unverified,
amountFrac: 0, value: "KUDOS:2",
amountVal: 2,
currency: "KUDOS", currency: "KUDOS",
listIssueDate: { t_s: 0 }, listIssueDate: { t_s: 0 },
}, },

View File

@ -699,25 +699,17 @@ export function selectWithdrawalDenominations(
let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency); let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate)); denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
denoms.sort((d1, d2) => denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
Amounts.cmp(
DenominationRecord.getValue(d2),
DenominationRecord.getValue(d1),
),
);
for (const d of denoms) { for (const d of denoms) {
const cost = Amounts.add( const cost = Amounts.add(d.value, d.fees.feeWithdraw).amount;
DenominationRecord.getValue(d),
d.fees.feeWithdraw,
).amount;
const res = Amounts.divmod(remaining, cost); const res = Amounts.divmod(remaining, cost);
const count = res.quotient; const count = res.quotient;
remaining = Amounts.sub(remaining, Amounts.mult(cost, count).amount).amount; remaining = Amounts.sub(remaining, Amounts.mult(cost, count).amount).amount;
if (count > 0) { if (count > 0) {
totalCoinValue = Amounts.add( totalCoinValue = Amounts.add(
totalCoinValue, totalCoinValue,
Amounts.mult(DenominationRecord.getValue(d), count).amount, Amounts.mult(d.value, count).amount,
).amount; ).amount;
totalWithdrawCost = Amounts.add( totalWithdrawCost = Amounts.add(
totalWithdrawCost, totalWithdrawCost,
@ -766,30 +758,22 @@ export function selectForcedWithdrawalDenominations(
let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency); let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate)); denoms = denoms.filter((d) => isWithdrawableDenom(d, denomselAllowLate));
denoms.sort((d1, d2) => denoms.sort((d1, d2) => Amounts.cmp(d2.value, d1.value));
Amounts.cmp(
DenominationRecord.getValue(d2),
DenominationRecord.getValue(d1),
),
);
for (const fds of forcedDenomSel.denoms) { for (const fds of forcedDenomSel.denoms) {
const count = fds.count; const count = fds.count;
const denom = denoms.find((x) => { const denom = denoms.find((x) => {
return Amounts.cmp(DenominationRecord.getValue(x), fds.value) == 0; return Amounts.cmp(x.value, fds.value) == 0;
}); });
if (!denom) { if (!denom) {
throw Error( throw Error(
`unable to find denom for forced selection (value ${fds.value})`, `unable to find denom for forced selection (value ${fds.value})`,
); );
} }
const cost = Amounts.add( const cost = Amounts.add(denom.value, denom.fees.feeWithdraw).amount;
DenominationRecord.getValue(denom),
denom.fees.feeWithdraw,
).amount;
totalCoinValue = Amounts.add( totalCoinValue = Amounts.add(
totalCoinValue, totalCoinValue,
Amounts.mult(DenominationRecord.getValue(denom), count).amount, Amounts.mult(denom.value, count).amount,
).amount; ).amount;
totalWithdrawCost = Amounts.add( totalWithdrawCost = Amounts.add(
totalWithdrawCost, totalWithdrawCost,

View File

@ -321,7 +321,7 @@ function buildCoinInfoFromDenom(
AbsoluteTime.fromProtocolTimestamp(denom.stampExpireDeposit), AbsoluteTime.fromProtocolTimestamp(denom.stampExpireDeposit),
), ),
totalAvailable: total, totalAvailable: total,
value: DenominationRecord.getValue(denom), value: Amounts.parseOrThrow(denom.value),
maxAge, maxAge,
}; };
} }

View File

@ -915,11 +915,7 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
coin_pub: c.coinPub, coin_pub: c.coinPub,
denom_pub: denomInfo.denomPub, denom_pub: denomInfo.denomPub,
denom_pub_hash: c.denomPubHash, denom_pub_hash: c.denomPubHash,
denom_value: Amounts.stringify({ denom_value: denom.value,
value: denom.amountVal,
currency: denom.currency,
fraction: denom.amountFrac,
}),
exchange_base_url: c.exchangeBaseUrl, exchange_base_url: c.exchangeBaseUrl,
refresh_parent_coin_pub: refreshParentCoinPub, refresh_parent_coin_pub: refreshParentCoinPub,
withdrawal_reserve_pub: withdrawalReservePub, withdrawal_reserve_pub: withdrawalReservePub,
@ -1876,35 +1872,27 @@ class InternalWalletStateImpl implements InternalWalletState {
return computeRefundTransactionState(rec); return computeRefundTransactionState(rec);
} }
case TransactionType.PeerPullCredit: case TransactionType.PeerPullCredit:
const rec = await tx.peerPullCredit.get( const rec = await tx.peerPullCredit.get(parsedTxId.pursePub);
parsedTxId.pursePub,
);
if (!rec) { if (!rec) {
return undefined; return undefined;
} }
return computePeerPullCreditTransactionState(rec); return computePeerPullCreditTransactionState(rec);
case TransactionType.PeerPullDebit: { case TransactionType.PeerPullDebit: {
const rec = await tx.peerPullDebit.get( const rec = await tx.peerPullDebit.get(parsedTxId.peerPullDebitId);
parsedTxId.peerPullDebitId,
);
if (!rec) { if (!rec) {
return undefined; return undefined;
} }
return computePeerPullDebitTransactionState(rec); return computePeerPullDebitTransactionState(rec);
} }
case TransactionType.PeerPushCredit: { case TransactionType.PeerPushCredit: {
const rec = await tx.peerPushCredit.get( const rec = await tx.peerPushCredit.get(parsedTxId.peerPushCreditId);
parsedTxId.peerPushCreditId,
);
if (!rec) { if (!rec) {
return undefined; return undefined;
} }
return computePeerPushCreditTransactionState(rec); return computePeerPushCreditTransactionState(rec);
} }
case TransactionType.PeerPushDebit: { case TransactionType.PeerPushDebit: {
const rec = await tx.peerPushDebit.get( const rec = await tx.peerPushDebit.get(parsedTxId.pursePub);
parsedTxId.pursePub,
);
if (!rec) { if (!rec) {
return undefined; return undefined;
} }