summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/anastasis-core/src/index.ts20
-rw-r--r--packages/taler-util/src/amounts.ts78
-rw-r--r--packages/taler-util/src/wallet-types.ts52
-rw-r--r--packages/taler-wallet-core/src/crypto/cryptoImplementation.ts16
-rw-r--r--packages/taler-wallet-core/src/crypto/cryptoTypes.ts4
-rw-r--r--packages/taler-wallet-core/src/db.ts59
-rw-r--r--packages/taler-wallet-core/src/dbless.ts6
-rw-r--r--packages/taler-wallet-core/src/operations/backup/import.ts80
-rw-r--r--packages/taler-wallet-core/src/operations/balance.ts16
-rw-r--r--packages/taler-wallet-core/src/operations/common.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/deposits.ts30
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts18
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts103
-rw-r--r--packages/taler-wallet-core/src/operations/pay-peer.ts12
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts32
-rw-r--r--packages/taler-wallet-core/src/operations/tip.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts41
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.test.ts96
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts26
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.ts2
-rw-r--r--packages/taler-wallet-core/src/util/denominations.test.ts5
-rw-r--r--packages/taler-wallet-core/src/util/denominations.ts11
-rw-r--r--packages/taler-wallet-core/src/wallet.ts2
-rw-r--r--packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx18
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts6
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx2
28 files changed, 400 insertions, 349 deletions
diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts
index eb2b41e50..8cb86cd85 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -169,8 +169,8 @@ export class ReducerError extends Error {
constructor(public errorJson: ErrorDetails) {
super(
errorJson.message ??
- errorJson.hint ??
- `${TalerErrorCode[errorJson.code]}`,
+ errorJson.hint ??
+ `${TalerErrorCode[errorJson.code]}`,
);
// Set the prototype explicitly.
@@ -306,7 +306,7 @@ async function getProviderInfo(
status: "error",
code: TalerErrorCode.ANASTASIS_REDUCER_PROVIDER_CONFIG_FAILED,
hint: "provider did not have provider salt",
- }
+ };
}
return {
status: "ok",
@@ -559,8 +559,8 @@ async function uploadSecret(
"content-type": "application/json",
...(paySecret
? {
- "Anastasis-Payment-Identifier": paySecret,
- }
+ "Anastasis-Payment-Identifier": paySecret,
+ }
: {}),
},
body: JSON.stringify(tur),
@@ -651,8 +651,8 @@ async function uploadSecret(
[ANASTASIS_HTTP_HEADER_POLICY_META_DATA]: metadataEnc,
...(paySecret
? {
- "Anastasis-Payment-Identifier": paySecret,
- }
+ "Anastasis-Payment-Identifier": paySecret,
+ }
: {}),
},
body: decodeCrock(encRecoveryDoc),
@@ -663,12 +663,12 @@ async function uploadSecret(
let policyExpiration: TalerProtocolTimestamp = { t_s: 0 };
try {
policyVersion = Number(resp.headers.get("Anastasis-Version") ?? "0");
- } catch (e) { }
+ } catch (e) {}
try {
policyExpiration = {
t_s: Number(resp.headers.get("Anastasis-Policy-Expiration") ?? "0"),
};
- } catch (e) { }
+ } catch (e) {}
successDetails[prov.provider_url] = {
policy_version: policyVersion,
policy_expiration: policyExpiration,
@@ -1469,7 +1469,7 @@ async function updateUploadFees(
const addFee = (x: AmountLike) => {
x = Amounts.jsonifyAmount(x);
feePerCurrency[x.currency] = Amounts.add(
- feePerCurrency[x.currency] ?? Amounts.getZero(x.currency),
+ feePerCurrency[x.currency] ?? Amounts.zeroOfAmount(x),
x,
).amount;
};
diff --git a/packages/taler-util/src/amounts.ts b/packages/taler-util/src/amounts.ts
index c9a78356e..f59e325b0 100644
--- a/packages/taler-util/src/amounts.ts
+++ b/packages/taler-util/src/amounts.ts
@@ -103,10 +103,24 @@ export class Amounts {
throw Error("not instantiable");
}
+ static currencyOf(amount: AmountLike) {
+ const amt = Amounts.parseOrThrow(amount);
+ return amt.currency;
+ }
+
+ static zeroOfAmount(amount: AmountLike): AmountJson {
+ const amt = Amounts.parseOrThrow(amount);
+ return {
+ currency: amt.currency,
+ fraction: 0,
+ value: 0,
+ };
+ }
+
/**
* Get an amount that represents zero units of a currency.
*/
- static getZero(currency: string): AmountJson {
+ static zeroOfCurrency(currency: string): AmountJson {
return {
currency,
fraction: 0,
@@ -132,7 +146,7 @@ export class Amounts {
static sumOrZero(currency: string, amounts: AmountLike[]): Result {
if (amounts.length <= 0) {
return {
- amount: Amounts.getZero(currency),
+ amount: Amounts.zeroOfCurrency(currency),
saturated: false,
};
}
@@ -147,9 +161,11 @@ export class Amounts {
*
* Throws when currencies don't match.
*/
- static add(first: AmountJson, ...rest: AmountJson[]): Result {
- const currency = first.currency;
- let value = first.value + Math.floor(first.fraction / amountFractionalBase);
+ static add(first: AmountLike, ...rest: AmountLike[]): Result {
+ const firstJ = Amounts.jsonifyAmount(first);
+ const currency = firstJ.currency;
+ let value =
+ firstJ.value + Math.floor(firstJ.fraction / amountFractionalBase);
if (value > amountMaxValue) {
return {
amount: {
@@ -160,17 +176,18 @@ export class Amounts {
saturated: true,
};
}
- let fraction = first.fraction % amountFractionalBase;
+ let fraction = firstJ.fraction % amountFractionalBase;
for (const x of rest) {
- if (x.currency.toUpperCase() !== currency.toUpperCase()) {
- throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
+ const xJ = Amounts.jsonifyAmount(x);
+ if (xJ.currency.toUpperCase() !== currency.toUpperCase()) {
+ throw Error(`Mismatched currency: ${xJ.currency} and ${currency}`);
}
value =
value +
- x.value +
- Math.floor((fraction + x.fraction) / amountFractionalBase);
- fraction = Math.floor((fraction + x.fraction) % amountFractionalBase);
+ xJ.value +
+ Math.floor((fraction + xJ.fraction) / amountFractionalBase);
+ fraction = Math.floor((fraction + xJ.fraction) % amountFractionalBase);
if (value > amountMaxValue) {
return {
amount: {
@@ -322,12 +339,27 @@ export class Amounts {
* Parse amount in standard string form (like 'EUR:20.5'),
* throw if the input is not a valid amount.
*/
- static parseOrThrow(s: string): AmountJson {
- const res = Amounts.parse(s);
- if (!res) {
- throw Error(`Can't parse amount: "${s}"`);
+ static parseOrThrow(s: AmountLike): AmountJson {
+ if (typeof s === "object") {
+ if (typeof s.currency !== "string") {
+ throw Error("invalid amount object");
+ }
+ if (typeof s.value !== "number") {
+ throw Error("invalid amount object");
+ }
+ if (typeof s.fraction !== "number") {
+ throw Error("invalid amount object");
+ }
+ return { currency: s.currency, value: s.value, fraction: s.fraction };
+ } else if (typeof s === "string") {
+ const res = Amounts.parse(s);
+ if (!res) {
+ throw Error(`Can't parse amount: "${s}"`);
+ }
+ return res;
+ } else {
+ throw Error("invalid amount (illegal type)");
}
- return res;
}
/**
@@ -371,10 +403,13 @@ export class Amounts {
throw Error("amount can only be multiplied by a positive integer");
}
if (n == 0) {
- return { amount: Amounts.getZero(a.currency), saturated: false };
+ return {
+ amount: Amounts.zeroOfCurrency(a.currency),
+ saturated: false,
+ };
}
let x = a;
- let acc = Amounts.getZero(a.currency);
+ let acc = Amounts.zeroOfCurrency(a.currency);
while (n > 1) {
if (n % 2 == 0) {
n = n / 2;
@@ -427,9 +462,10 @@ export class Amounts {
return x1.currency.toUpperCase() === x2.currency.toUpperCase();
}
- static stringifyValue(a: AmountJson, minFractional = 0): string {
- const av = a.value + Math.floor(a.fraction / amountFractionalBase);
- const af = a.fraction % amountFractionalBase;
+ static stringifyValue(a: AmountLike, minFractional = 0): string {
+ const aJ = Amounts.jsonifyAmount(a);
+ const av = aJ.value + Math.floor(aJ.fraction / amountFractionalBase);
+ const af = aJ.fraction % amountFractionalBase;
let s = av.toString();
if (af) {
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index 5ff906faa..5d1c55b88 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -644,7 +644,7 @@ export enum RefreshReason {
*/
export interface CoinRefreshRequest {
readonly coinPub: string;
- readonly amount: AmountJson;
+ readonly amount: AmountString;
}
/**
@@ -719,12 +719,12 @@ export interface WireFee {
/**
* Fee for wire transfers.
*/
- wireFee: AmountJson;
+ wireFee: AmountString;
/**
* Fees to close and refund a reserve.
*/
- closingFee: AmountJson;
+ closingFee: AmountString;
/**
* Start date of the fee.
@@ -761,9 +761,9 @@ export interface ExchangeGlobalFees {
startDate: TalerProtocolTimestamp;
endDate: TalerProtocolTimestamp;
- historyFee: AmountJson;
- accountFee: AmountJson;
- purseFee: AmountJson;
+ historyFee: AmountString;
+ accountFee: AmountString;
+ purseFee: AmountString;
historyTimeout: TalerProtocolDuration;
purseTimeout: TalerProtocolDuration;
@@ -782,8 +782,8 @@ const codecForExchangeAccount = (): Codec<ExchangeAccount> =>
const codecForWireFee = (): Codec<WireFee> =>
buildCodecForObject<WireFee>()
.property("sig", codecForString())
- .property("wireFee", codecForAmountJson())
- .property("closingFee", codecForAmountJson())
+ .property("wireFee", codecForAmountString())
+ .property("closingFee", codecForAmountString())
.property("startStamp", codecForTimestamp)
.property("endStamp", codecForTimestamp)
.build("codecForWireFee");
@@ -798,7 +798,7 @@ export interface DenominationInfo {
/**
* Value of one coin of the denomination.
*/
- value: AmountJson;
+ value: AmountString;
/**
* Hash of the denomination public key.
@@ -811,22 +811,22 @@ export interface DenominationInfo {
/**
* Fee for withdrawing.
*/
- feeWithdraw: AmountJson;
+ feeWithdraw: AmountString;
/**
* Fee for depositing.
*/
- feeDeposit: AmountJson;
+ feeDeposit: AmountString;
/**
* Fee for refreshing.
*/
- feeRefresh: AmountJson;
+ feeRefresh: AmountString;
/**
* Fee for refunding.
*/
- feeRefund: AmountJson;
+ feeRefund: AmountString;
/**
* Validity start date of the denomination.
@@ -858,21 +858,21 @@ export interface FeeDescription {
group: string;
from: AbsoluteTime;
until: AbsoluteTime;
- fee?: AmountJson;
+ fee?: AmountString;
}
export interface FeeDescriptionPair {
group: string;
from: AbsoluteTime;
until: AbsoluteTime;
- left?: AmountJson;
- right?: AmountJson;
+ left?: AmountString;
+ right?: AmountString;
}
export interface TimePoint<T> {
id: string;
group: string;
- fee: AmountJson;
+ fee: AmountString;
type: "start" | "end";
moment: AbsoluteTime;
denom: T;
@@ -955,8 +955,8 @@ export const codecForFeeDescriptionPair = (): Codec<FeeDescriptionPair> =>
.property("group", codecForString())
.property("from", codecForAbsoluteTime)
.property("until", codecForAbsoluteTime)
- .property("left", codecOptional(codecForAmountJson()))
- .property("right", codecOptional(codecForAmountJson()))
+ .property("left", codecOptional(codecForAmountString()))
+ .property("right", codecOptional(codecForAmountString()))
.build("FeeDescriptionPair");
export const codecForFeeDescription = (): Codec<FeeDescription> =>
@@ -964,7 +964,7 @@ export const codecForFeeDescription = (): Codec<FeeDescription> =>
.property("group", codecForString())
.property("from", codecForAbsoluteTime)
.property("until", codecForAbsoluteTime)
- .property("fee", codecOptional(codecForAmountJson()))
+ .property("fee", codecOptional(codecForAmountString()))
.build("FeeDescription");
export const codecForFeesByOperations = (): Codec<
@@ -1056,8 +1056,8 @@ export interface ManualWithdrawalDetails {
* Selected denominations withn some extra info.
*/
export interface DenomSelectionState {
- totalCoinValue: AmountJson;
- totalWithdrawCost: AmountJson;
+ totalCoinValue: AmountString;
+ totalWithdrawCost: AmountString;
selectedDenoms: {
denomPubHash: string;
count: number;
@@ -1786,7 +1786,7 @@ export interface PayCoinSelection {
/**
* Amount requested by the merchant.
*/
- paymentAmount: AmountJson;
+ paymentAmount: AmountString;
/**
* Public keys of the coins that were selected.
@@ -1796,17 +1796,17 @@ export interface PayCoinSelection {
/**
* Amount that each coin contributes.
*/
- coinContributions: AmountJson[];
+ coinContributions: AmountString[];
/**
* How much of the wire fees is the customer paying?
*/
- customerWireFees: AmountJson;
+ customerWireFees: AmountString;
/**
* How much of the deposit fees is the customer paying?
*/
- customerDepositFees: AmountJson;
+ customerDepositFees: AmountString;
}
export interface InitiatePeerPushPaymentRequest {
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index 8ba7d9298..d239270c8 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -28,6 +28,7 @@ import {
AgeCommitmentProof,
AgeRestriction,
AmountJson,
+ AmountLike,
Amounts,
AmountString,
BlindedDenominationSignature,
@@ -1155,8 +1156,8 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
sessionSecretSeed: refreshSessionSecretSeed,
} = req;
- const currency = newCoinDenoms[0].value.currency;
- let valueWithFee = Amounts.getZero(currency);
+ const currency = Amounts.currencyOf(newCoinDenoms[0].value);
+ let valueWithFee = Amounts.zeroOfCurrency(currency);
for (const ncd of newCoinDenoms) {
const t = Amounts.add(ncd.value, ncd.feeWithdraw).amount;
@@ -1627,21 +1628,22 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
},
};
-function amountToBuffer(amount: AmountJson): Uint8Array {
+function amountToBuffer(amount: AmountLike): Uint8Array {
+ const amountJ = Amounts.jsonifyAmount(amount);
const buffer = new ArrayBuffer(8 + 4 + 12);
const dvbuf = new DataView(buffer);
const u8buf = new Uint8Array(buffer);
- const curr = stringToBytes(amount.currency);
+ const curr = stringToBytes(amountJ.currency);
if (typeof dvbuf.setBigUint64 !== "undefined") {
- dvbuf.setBigUint64(0, BigInt(amount.value));
+ dvbuf.setBigUint64(0, BigInt(amountJ.value));
} else {
- const arr = bigint(amount.value).toArray(2 ** 8).value;
+ const arr = bigint(amountJ.value).toArray(2 ** 8).value;
let offset = 8 - arr.length;
for (let i = 0; i < arr.length; i++) {
dvbuf.setUint8(offset++, arr[i]);
}
}
- dvbuf.setUint32(8, amount.fraction);
+ dvbuf.setUint32(8, amountJ.fraction);
u8buf.set(curr, 8 + 4);
return u8buf;
diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
index 0858cffa9..a083f453c 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
@@ -44,8 +44,8 @@ import {
export interface RefreshNewDenomInfo {
count: number;
- value: AmountJson;
- feeWithdraw: AmountJson;
+ value: AmountString;
+ feeWithdraw: AmountString;
denomPub: DenominationPubKey;
denomPubHash: string;
}
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 12e7820c2..0b27b82dd 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -47,6 +47,7 @@ import {
UnblindedSignature,
WireInfo,
HashCodeString,
+ Amounts,
} from "@gnu-taler/taler-util";
import {
describeContents,
@@ -276,22 +277,22 @@ export interface DenomFees {
/**
* Fee for withdrawing.
*/
- feeWithdraw: AmountJson;
+ feeWithdraw: AmountString;
/**
* Fee for depositing.
*/
- feeDeposit: AmountJson;
+ feeDeposit: AmountString;
/**
* Fee for refreshing.
*/
- feeRefresh: AmountJson;
+ feeRefresh: AmountString;
/**
* Fee for refunding.
*/
- feeRefund: AmountJson;
+ feeRefund: AmountString;
}
/**
@@ -393,15 +394,15 @@ export namespace DenominationRecord {
return {
denomPub: d.denomPub,
denomPubHash: d.denomPubHash,
- feeDeposit: d.fees.feeDeposit,
- feeRefresh: d.fees.feeRefresh,
- feeRefund: d.fees.feeRefund,
- feeWithdraw: d.fees.feeWithdraw,
+ feeDeposit: Amounts.stringify(d.fees.feeDeposit),
+ feeRefresh: Amounts.stringify(d.fees.feeRefresh),
+ feeRefund: Amounts.stringify(d.fees.feeRefund),
+ feeWithdraw: Amounts.stringify(d.fees.feeWithdraw),
stampExpireDeposit: d.stampExpireDeposit,
stampExpireLegal: d.stampExpireLegal,
stampExpireWithdraw: d.stampExpireWithdraw,
stampStart: d.stampStart,
- value: DenominationRecord.getValue(d),
+ value: Amounts.stringify(DenominationRecord.getValue(d)),
exchangeBaseUrl: d.exchangeBaseUrl,
};
}
@@ -527,7 +528,7 @@ export interface ExchangeRecord {
* currency.
*
* We could use a rowID here, but having the currency in the
- * details pointer lets us do fewer DB queries sometimes.
+ * details pointer lets us do fewer DB queries
*/
detailsPointer: ExchangeDetailsPointer | undefined;
@@ -752,12 +753,12 @@ export interface TipRecord {
/**
* The tipped amount.
*/
- tipAmountRaw: AmountJson;
+ tipAmountRaw: AmountString;
/**
* Effect on the balance (including fees etc).
*/
- tipAmountEffective: AmountJson;
+ tipAmountEffective: AmountString;
/**
* Timestamp, the tip can't be picked up anymore after this deadline.
@@ -854,9 +855,9 @@ export interface RefreshGroupRecord {
// object store for faster updates?
refreshSessionPerCoin: (RefreshSessionRecord | undefined)[];
- inputPerCoin: AmountJson[];
+ inputPerCoin: AmountString[];
- estimatedOutputPerCoin: AmountJson[];
+ estimatedOutputPerCoin: AmountString[];
/**
* Flag for each coin whether refreshing finished.
@@ -888,7 +889,7 @@ export interface RefreshSessionRecord {
* Sum of the value of denominations we want
* to withdraw in this session, without fees.
*/
- amountRefreshOutput: AmountJson;
+ amountRefreshOutput: AmountString;
/**
* Hashed denominations of the newly requested coins.
@@ -927,9 +928,9 @@ export interface WalletRefundItemCommon {
*/
obtainedTime: TalerProtocolTimestamp;
- refundAmount: AmountJson;
+ refundAmount: AmountString;
- refundFee: AmountJson;
+ refundFee: AmountString;
/**
* Upper bound on the refresh cost incurred by
@@ -938,7 +939,7 @@ export interface WalletRefundItemCommon {
* Might be lower in practice when two refunds on the same
* coin are refreshed in the same refresh operation.
*/
- totalRefreshCostBound: AmountJson;
+ totalRefreshCostBound: AmountString;
coinPub: string;
@@ -1003,12 +1004,12 @@ export interface WalletContractData {
merchantSig: string;
merchantPub: string;
merchant: MerchantInfo;
- amount: AmountJson;
+ amount: AmountString;
orderId: string;
merchantBaseUrl: string;
summary: string;
autoRefund: TalerProtocolDuration | undefined;
- maxWireFee: AmountJson;
+ maxWireFee: AmountString;
wireFeeAmortization: number;
payDeadline: TalerProtocolTimestamp;
refundDeadline: TalerProtocolTimestamp;
@@ -1017,7 +1018,7 @@ export interface WalletContractData {
timestamp: TalerProtocolTimestamp;
wireMethod: string;
wireInfoHash: string;
- maxDepositFee: AmountJson;
+ maxDepositFee: AmountString;
minimumAge?: number;
deliveryDate: TalerProtocolTimestamp | undefined;
deliveryLocation: Location | undefined;
@@ -1099,7 +1100,7 @@ export interface ProposalDownloadInfo {
export interface PurchasePayInfo {
payCoinSelection: PayCoinSelection;
- totalPayCost: AmountJson;
+ totalPayCost: AmountString;
payCoinSelectionUid: string;
}
@@ -1216,7 +1217,7 @@ export interface PurchaseRecord {
* How much merchant has refund to be taken but the wallet
* did not picked up yet
*/
- refundAmountAwaiting: AmountJson | undefined;
+ refundAmountAwaiting: AmountString | undefined;
}
export enum ConfigRecordKey {
@@ -1379,7 +1380,7 @@ export interface WithdrawalGroupRecord {
/**
* Amount that was sent by the user to fund the reserve.
*/
- instructedAmount: AmountJson;
+ instructedAmount: AmountString;
/**
* Amount that was observed when querying the reserve that
@@ -1387,7 +1388,7 @@ export interface WithdrawalGroupRecord {
*
* Useful for diagnostics.
*/
- reserveBalanceAmount?: AmountJson;
+ reserveBalanceAmount?: AmountString;
/**
* Amount including fees (i.e. the amount subtracted from the
@@ -1396,7 +1397,7 @@ export interface WithdrawalGroupRecord {
* (Initial amount confirmed by the user, might differ with denomSel
* on reselection.)
*/
- rawWithdrawalAmount: AmountJson;
+ rawWithdrawalAmount: AmountString;
/**
* Amount that will be added to the balance when the withdrawal succeeds.
@@ -1404,7 +1405,7 @@ export interface WithdrawalGroupRecord {
* (Initial amount confirmed by the user, might differ with denomSel
* on reselection.)
*/
- effectiveWithdrawalAmount: AmountJson;
+ effectiveWithdrawalAmount: AmountString;
/**
* Denominations selected for withdrawal.
@@ -1587,9 +1588,9 @@ export interface DepositGroupRecord {
payCoinSelectionUid: string;
- totalPayCost: AmountJson;
+ totalPayCost: AmountString;
- effectiveDepositAmount: AmountJson;
+ effectiveDepositAmount: AmountString;
depositedPerCoin: boolean[];
diff --git a/packages/taler-wallet-core/src/dbless.ts b/packages/taler-wallet-core/src/dbless.ts
index 076e5f215..544e2d458 100644
--- a/packages/taler-wallet-core/src/dbless.ts
+++ b/packages/taler-wallet-core/src/dbless.ts
@@ -160,7 +160,7 @@ export async function withdrawCoin(args: {
const planchet = await cryptoApi.createPlanchet({
coinIndex: 0,
denomPub: denom.denomPub,
- feeWithdraw: denom.fees.feeWithdraw,
+ feeWithdraw: Amounts.parseOrThrow(denom.fees.feeWithdraw),
reservePriv: reserveKeyPair.reservePriv,
reservePub: reserveKeyPair.reservePub,
secretSeed: encodeCrock(getRandomBytes(32)),
@@ -294,11 +294,11 @@ export async function refreshCoin(req: {
denomPub: x.denomPub,
denomPubHash: x.denomPubHash,
feeWithdraw: x.fees.feeWithdraw,
- value: {
+ value: Amounts.stringify({
currency: x.currency,
fraction: x.amountFrac,
value: x.amountVal,
- },
+ }),
})),
meltCoinMaxAge: oldCoin.maxAge,
});
diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts
index 133699647..3159c60af 100644
--- a/packages/taler-wallet-core/src/operations/backup/import.ts
+++ b/packages/taler-wallet-core/src/operations/backup/import.ts
@@ -104,10 +104,8 @@ async function recoverPayCoinSelection(
const coveredExchanges: Set<string> = new Set();
- let totalWireFee: AmountJson = Amounts.getZero(contractData.amount.currency);
- let totalDepositFees: AmountJson = Amounts.getZero(
- contractData.amount.currency,
- );
+ let totalWireFee: AmountJson = Amounts.zeroOfAmount(contractData.amount);
+ let totalDepositFees: AmountJson = Amounts.zeroOfAmount(contractData.amount);
for (const coinPub of coinPubs) {
const coinRecord = await tx.coins.get(coinPub);
@@ -136,7 +134,7 @@ async function recoverPayCoinSelection(
fee.startStamp <= contractData.timestamp &&
fee.endStamp >= contractData.timestamp
) {
- wireFee = fee.wireFee;
+ wireFee = Amounts.parseOrThrow(fee.wireFee);
break;
}
}
@@ -156,7 +154,7 @@ async function recoverPayCoinSelection(
if (Amounts.cmp(contractData.maxWireFee, amortizedWireFee) < 0) {
customerWireFee = amortizedWireFee;
} else {
- customerWireFee = Amounts.getZero(contractData.amount.currency);
+ customerWireFee = Amounts.zeroOfAmount(contractData.amount);
}
const customerDepositFees = Amounts.sub(
@@ -166,10 +164,10 @@ async function recoverPayCoinSelection(
return {
coinPubs,
- coinContributions,
- paymentAmount: contractData.amount,
- customerWireFees: customerWireFee,
- customerDepositFees,
+ coinContributions: coinContributions.map((x) => Amounts.stringify(x)),
+ paymentAmount: Amounts.stringify(contractData.amount),
+ customerWireFees: Amounts.stringify(customerWireFee),
+ customerDepositFees: Amounts.stringify(customerDepositFees),
};
}
@@ -183,8 +181,8 @@ async function getDenomSelStateFromBackup(
denomPubHash: string;
count: number;
}[] = [];
- let totalCoinValue = Amounts.getZero(currency);
- let totalWithdrawCost = Amounts.getZero(currency);
+ let totalCoinValue = Amounts.zeroOfCurrency(currency);
+ let totalWithdrawCost = Amounts.zeroOfCurrency(currency);
for (const s of sel) {
const d = await tx.denominations.get([exchangeBaseUrl, s.denom_pub_hash]);
checkBackupInvariant(!!d);
@@ -200,8 +198,8 @@ async function getDenomSelStateFromBackup(
}
return {
selectedDenoms,
- totalCoinValue,
- totalWithdrawCost,
+ totalCoinValue: Amounts.stringify(totalCoinValue),
+ totalWithdrawCost: Amounts.stringify(totalCoinValue),
};
}
@@ -380,11 +378,11 @@ export async function importBackup(
for (const fee of backupExchangeDetails.wire_fees) {
const w = (wireInfo.feesForType[fee.wire_type] ??= []);
w.push({
- closingFee: Amounts.parseOrThrow(fee.closing_fee),
+ closingFee: Amounts.stringify(fee.closing_fee),
endStamp: fee.end_stamp,
sig: fee.sig,
startStamp: fee.start_stamp,
- wireFee: Amounts.parseOrThrow(fee.wire_fee),
+ wireFee: Amounts.stringify(fee.wire_fee),
});
}
let tosAccepted = undefined;
@@ -412,9 +410,9 @@ export async function importBackup(
tosCurrentEtag: backupExchangeDetails.tos_accepted_etag || "",
tosAccepted,
globalFees: backupExchangeDetails.global_fees.map((x) => ({
- accountFee: Amounts.parseOrThrow(x.accountFee),
- historyFee: Amounts.parseOrThrow(x.historyFee),
- purseFee: Amounts.parseOrThrow(x.purseFee),
+ accountFee: Amounts.stringify(x.accountFee),
+ historyFee: Amounts.stringify(x.historyFee),
+ purseFee: Amounts.stringify(x.purseFee),
endDate: x.endDate,
historyTimeout: x.historyTimeout,
signature: x.signature,
@@ -447,16 +445,10 @@ export async function importBackup(
exchangeBaseUrl: backupExchangeDetails.base_url,
exchangeMasterPub: backupExchangeDetails.master_public_key,
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,
- ),
+ feeDeposit: Amounts.stringify(backupDenomination.fee_deposit),
+ feeRefresh: Amounts.stringify(backupDenomination.fee_refresh),
+ feeRefund: Amounts.stringify(backupDenomination.fee_refund),
+ feeWithdraw: Amounts.stringify(backupDenomination.fee_withdraw),
},
isOffered: backupDenomination.is_offered,
isRevoked: backupDenomination.is_revoked,
@@ -542,7 +534,7 @@ export async function importBackup(
await tx.withdrawalGroups.put({
withdrawalGroupId: backupWg.withdrawal_group_id,
exchangeBaseUrl: backupWg.exchange_base_url,
- instructedAmount,
+ instructedAmount: Amounts.stringify(instructedAmount),
secretSeed: backupWg.secret_seed,
denomsSel: await getDenomSelStateFromBackup(
tx,
@@ -551,10 +543,10 @@ export async function importBackup(
backupWg.selected_denoms,
),
denomSelUid: backupWg.selected_denoms_uid,
- rawWithdrawalAmount: Amounts.parseOrThrow(
+ rawWithdrawalAmount: Amounts.stringify(
backupWg.raw_withdrawal_amount,
),
- effectiveWithdrawalAmount: Amounts.parseOrThrow(
+ effectiveWithdrawalAmount: Amounts.stringify(
backupWg.effective_withdrawal_amount,
),
reservePriv: backupWg.reserve_priv,
@@ -618,10 +610,10 @@ export async function importBackup(
coinPub: backupRefund.coin_pub,
executionTime: backupRefund.execution_time,
obtainedTime: backupRefund.obtained_time,
- refundAmount: Amounts.parseOrThrow(backupRefund.refund_amount),
- refundFee: denom.fees.feeRefund,
+ refundAmount: Amounts.stringify(backupRefund.refund_amount),
+ refundFee: Amounts.stringify(denom.fees.feeRefund),
rtransactionId: backupRefund.rtransaction_id,
- totalRefreshCostBound: Amounts.parseOrThrow(
+ totalRefreshCostBound: Amounts.stringify(
backupRefund.total_refresh_cost_bound,
),
};
@@ -658,7 +650,7 @@ export async function importBackup(
if (parsedContractTerms.max_wire_fee) {
maxWireFee = Amounts.parseOrThrow(parsedContractTerms.max_wire_fee);
} else {
- maxWireFee = Amounts.getZero(amount.currency);
+ maxWireFee = Amounts.zeroOfCurrency(amount.currency);
}
const download: ProposalDownloadInfo = {
contractTermsHash,
@@ -682,7 +674,7 @@ export async function importBackup(
backupPurchase.pay_info,
),
payCoinSelectionUid: backupPurchase.pay_info.pay_coins_uid,
- totalPayCost: Amounts.parseOrThrow(
+ totalPayCost: Amounts.stringify(
backupPurchase.pay_info.total_pay_cost,
),
};
@@ -776,7 +768,7 @@ export async function importBackup(
count: x.count,
denomPubHash: x.denom_pub_hash,
})),
- amountRefreshOutput: denomSel.totalCoinValue,
+ amountRefreshOutput: Amounts.stringify(denomSel.totalCoinValue),
});
} else {
refreshSessionPerCoin.push(undefined);
@@ -797,11 +789,11 @@ export async function importBackup(
operationStatus: backupRefreshGroup.timestamp_finish
? RefreshOperationStatus.Finished
: RefreshOperationStatus.Pending,
- inputPerCoin: backupRefreshGroup.old_coins.map((x) =>
- Amounts.parseOrThrow(x.input_amount),
+ inputPerCoin: backupRefreshGroup.old_coins.map(
+ (x) => x.input_amount,
),
- estimatedOutputPerCoin: backupRefreshGroup.old_coins.map((x) =>
- Amounts.parseOrThrow(x.estimated_output_amount),
+ estimatedOutputPerCoin: backupRefreshGroup.old_coins.map(
+ (x) => x.estimated_output_amount,
),
refreshSessionPerCoin,
});
@@ -834,8 +826,8 @@ export async function importBackup(
merchantTipId: backupTip.merchant_tip_id,
pickedUpTimestamp: backupTip.timestamp_finished,
secretSeed: backupTip.secret_seed,
- tipAmountEffective: denomsSel.totalCoinValue,
- tipAmountRaw,
+ tipAmountEffective: Amounts.stringify(denomsSel.totalCoinValue),
+ tipAmountRaw: Amounts.stringify(tipAmountRaw),
tipExpiration: backupTip.timestamp_expiration,
walletTipId: backupTip.wallet_tip_id,
denomSelUid: backupTip.selected_denoms_uid,
diff --git a/packages/taler-wallet-core/src/operations/balance.ts b/packages/taler-wallet-core/src/operations/balance.ts
index 3db66b5d9..cd78b0360 100644
--- a/packages/taler-wallet-core/src/operations/balance.ts
+++ b/packages/taler-wallet-core/src/operations/balance.ts
@@ -57,9 +57,9 @@ export async function getBalancesInsideTransaction(
const b = balanceStore[currency];
if (!b) {
balanceStore[currency] = {
- available: Amounts.getZero(currency),
- pendingIncoming: Amounts.getZero(currency),
- pendingOutgoing: Amounts.getZero(currency),
+ available: Amounts.zeroOfCurrency(currency),
+ pendingIncoming: Amounts.zeroOfCurrency(currency),
+ pendingOutgoing: Amounts.zeroOfCurrency(currency),
};
}
return balanceStore[currency];
@@ -85,7 +85,10 @@ export async function getBalancesInsideTransaction(
for (let i = 0; i < r.oldCoinPubs.length; i++) {
const session = r.refreshSessionPerCoin[i];
if (session) {
- const b = initBalance(session.amountRefreshOutput.currency);
+ const currency = Amounts.parseOrThrow(
+ session.amountRefreshOutput,
+ ).currency;
+ const b = initBalance(currency);
// We are always assuming the refresh will succeed, thus we
// report the output as available balance.
b.available = Amounts.add(
@@ -93,7 +96,8 @@ export async function getBalancesInsideTransaction(
session.amountRefreshOutput,
).amount;
} else {
- const b = initBalance(r.inputPerCoin[i].currency);
+ const currency = Amounts.parseOrThrow(r.inputPerCoin[i]).currency;
+ const b = initBalance(currency);
b.available = Amounts.add(
b.available,
r.estimatedOutputPerCoin[i],
@@ -106,7 +110,7 @@ export async function getBalancesInsideTransaction(
if (wds.timestampFinish) {
return;
}
- const b = initBalance(wds.denomsSel.totalWithdrawCost.currency);
+ const b = initBalance(Amounts.currencyOf(wds.denomsSel.totalWithdrawCost));
b.pendingIncoming = Amounts.add(
b.pendingIncoming,
wds.denomsSel.totalCoinValue,
diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts
index f35556736..73d1ee4b0 100644
--- a/packages/taler-wallet-core/src/operations/common.ts
+++ b/packages/taler-wallet-core/src/operations/common.ts
@@ -160,7 +160,7 @@ export async function spendCoins(
throw Error("not enough remaining balance on coin for payment");
}
refreshCoinPubs.push({
- amount: remaining.amount,
+ amount: Amounts.stringify(remaining.amount),
coinPub: coin.coinPub,
});
checkDbInvariant(!!coinAvailability);
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts
index b2bd18260..6ac4f3986 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -348,10 +348,10 @@ export async function prepareDepositGroup(
auditors: contractData.allowedAuditors,
exchanges: contractData.allowedExchanges,
wireMethod: contractData.wireMethod,
- contractTermsAmount: contractData.amount,
- depositFeeLimit: contractData.maxDepositFee,
+ contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
+ depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
- wireFeeLimit: contractData.maxWireFee,
+ wireFeeLimit: Amounts.parseOrThrow(contractData.maxWireFee),
prevPayCoins: [],
});
@@ -445,10 +445,10 @@ export async function createDepositGroup(
auditors: contractData.allowedAuditors,
exchanges: contractData.allowedExchanges,
wireMethod: contractData.wireMethod,
- contractTermsAmount: contractData.amount,
- depositFeeLimit: contractData.maxDepositFee,
+ contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
+ depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
- wireFeeLimit: contractData.maxWireFee,
+ wireFeeLimit: Amounts.parseOrThrow(contractData.maxWireFee),
prevPayCoins: [],
});
@@ -479,8 +479,8 @@ export async function createDepositGroup(
depositedPerCoin: payCoinSel.coinPubs.map(() => false),
merchantPriv: merchantPair.priv,
merchantPub: merchantPair.pub,
- totalPayCost: totalDepositCost,
- effectiveDepositAmount,
+ totalPayCost: Amounts.stringify(totalDepositCost),
+ effectiveDepositAmount: Amounts.stringify(effectiveDepositAmount),
wire: {
payto_uri: req.depositPaytoUri,
salt: wireSalt,
@@ -501,7 +501,9 @@ export async function createDepositGroup(
await spendCoins(ws, tx, {
allocationId: `txn:deposit:${depositGroup.depositGroupId}`,
coinPubs: payCoinSel.coinPubs,
- contributions: payCoinSel.coinContributions,
+ contributions: payCoinSel.coinContributions.map((x) =>
+ Amounts.parseOrThrow(x),
+ ),
refreshReason: RefreshReason.PayDeposit,
});
await tx.depositGroups.put(depositGroup);
@@ -543,8 +545,8 @@ export async function getEffectiveDepositAmount(
if (!denom) {
throw Error("can't find denomination to calculate deposit amount");
}
- amt.push(pcs.coinContributions[i]);
- fees.push(denom.feeDeposit);
+ amt.push(Amounts.parseOrThrow(pcs.coinContributions[i]));
+ fees.push(Amounts.parseOrThrow(denom.feeDeposit));
exchangeSet.add(coin.exchangeBaseUrl);
}
@@ -565,7 +567,7 @@ export async function getEffectiveDepositAmount(
);
})?.wireFee;
if (fee) {
- fees.push(fee);
+ fees.push(Amounts.parseOrThrow(fee));
}
}
});
@@ -604,7 +606,7 @@ export async function getTotalFeesForDepositAmount(
if (!denom) {
throw Error("can't find denomination to calculate deposit amount");
}
- coinFee.push(denom.feeDeposit);
+ coinFee.push(Amounts.parseOrThrow(denom.feeDeposit));
exchangeSet.add(coin.exchangeBaseUrl);
const allDenoms = await tx.denominations.indexes.byExchangeBaseUrl
@@ -638,7 +640,7 @@ export async function getTotalFeesForDepositAmount(
},
)?.wireFee;
if (fee) {
- wireFee.push(fee);
+ wireFee.push(Amounts.parseOrThrow(fee));
}
}
});
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index 23ff1479e..b6e2a9d73 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -98,10 +98,10 @@ function denominationRecordFromKeys(
exchangeBaseUrl,
exchangeMasterPub,
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),
+ feeDeposit: Amounts.stringify(denomIn.fee_deposit),
+ feeRefresh: Amounts.stringify(denomIn.fee_refresh),
+ feeRefund: Amounts.stringify(denomIn.fee_refund),
+ feeWithdraw: Amounts.stringify(denomIn.fee_withdraw),
},
isOffered: true,
isRevoked: false,
@@ -267,11 +267,11 @@ async function validateWireInfo(
const startStamp = x.start_date;
const endStamp = x.end_date;
const fee: WireFee = {
- closingFee: Amounts.parseOrThrow(x.closing_fee),
+ closingFee: Amounts.stringify(x.closing_fee),
endStamp,
sig: x.sig,
startStamp,
- wireFee: Amounts.parseOrThrow(x.wire_fee),
+ wireFee: Amounts.stringify(x.wire_fee),
};
let isValid = false;
if (ws.insecureTrustExchange) {
@@ -321,9 +321,9 @@ async function validateGlobalFees(
throw Error("exchange global fees signature invalid: " + gf.master_sig);
}
egf.push({
- accountFee: Amounts.parseOrThrow(gf.account_fee),
- historyFee: Amounts.parseOrThrow(gf.history_fee),
- purseFee: Amounts.parseOrThrow(gf.purse_fee),
+ accountFee: Amounts.stringify(gf.account_fee),
+ historyFee: Amounts.stringify(gf.history_fee),
+ purseFee: Amounts.stringify(gf.purse_fee),
startDate: gf.start_date,
endDate: gf.end_date,
signature: gf.master_sig,
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 2eb5b18e9..4483a57c0 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -182,10 +182,10 @@ export async function getTotalPaymentCost(
DenominationRecord.toDenomInfo(denom),
amountLeft,
);
- costs.push(pcs.coinContributions[i]);
+ costs.push(Amounts.parseOrThrow(pcs.coinContributions[i]));
costs.push(refreshCost);
}
- const zero = Amounts.getZero(pcs.paymentAmount.currency);
+ const zero = Amounts.zeroOfAmount(pcs.paymentAmount);
return Amounts.sum([zero, ...costs]).amount;
});
}
@@ -307,10 +307,10 @@ export function extractContractData(
if (parsedContractTerms.max_wire_fee) {
maxWireFee = Amounts.parseOrThrow(parsedContractTerms.max_wire_fee);
} else {
- maxWireFee = Amounts.getZero(amount.currency);
+ maxWireFee = Amounts.zeroOfCurrency(amount.currency);
}
return {
- amount,
+ amount: Amounts.stringify(amount),
contractTermsHash: contractTermsHash,
fulfillmentUrl: parsedContractTerms.fulfillment_url ?? "",
merchantBaseUrl: parsedContractTerms.merchant_base_url,
@@ -319,7 +319,7 @@ export function extractContractData(
orderId: parsedContractTerms.order_id,
summary: parsedContractTerms.summary,
autoRefund: parsedContractTerms.auto_refund,
- maxWireFee,
+ maxWireFee: Amounts.stringify(maxWireFee),
payDeadline: parsedContractTerms.pay_deadline,
refundDeadline: parsedContractTerms.refund_deadline,
wireFeeAmortization: parsedContractTerms.wire_fee_amortization || 1,
@@ -334,7 +334,7 @@ export function extractContractData(
timestamp: parsedContractTerms.timestamp,
wireMethod: parsedContractTerms.wire_method,
wireInfoHash: parsedContractTerms.h_wire,
- maxDepositFee: Amounts.parseOrThrow(parsedContractTerms.max_fee),
+ maxDepositFee: Amounts.stringify(parsedContractTerms.max_fee),
merchant: parsedContractTerms.merchant,
products: parsedContractTerms.products,
summaryI18n: parsedContractTerms.summary_i18n,
@@ -539,7 +539,7 @@ export async function processDownloadProposal(
p.download = {
contractTermsHash,
contractTermsMerchantSig: contractData.merchantSig,
- currency: contractData.amount.currency,
+ currency: Amounts.currencyOf(contractData.amount),
fulfillmentUrl: contractData.fulfillmentUrl,
};
await tx.contractTerms.put({
@@ -825,9 +825,9 @@ async function handleInsufficientFunds(
}
prevPayCoins.push({
coinPub,
- contribution: contrib,
+ contribution: Amounts.parseOrThrow(contrib),
exchangeBaseUrl: coin.exchangeBaseUrl,
- feeDeposit: denom.fees.feeDeposit,
+ feeDeposit: Amounts.parseOrThrow(denom.fees.feeDeposit),
});
}
});
@@ -836,10 +836,10 @@ async function handleInsufficientFunds(
auditors: contractData.allowedAuditors,
exchanges: contractData.allowedExchanges,
wireMethod: contractData.wireMethod,
- contractTermsAmount: contractData.amount,
- depositFeeLimit: contractData.maxDepositFee,
+ contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
+ depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
- wireFeeLimit: contractData.maxWireFee,
+ wireFeeLimit: Amounts.parseOrThrow(contractData.maxWireFee),
prevPayCoins,
requiredMinimumAge: contractData.minimumAge,
});
@@ -875,7 +875,9 @@ async function handleInsufficientFunds(
await spendCoins(ws, tx, {
allocationId: `txn:proposal:${p.proposalId}`,
coinPubs: payInfo.payCoinSelection.coinPubs,
- contributions: payInfo.payCoinSelection.coinContributions,
+ contributions: payInfo.payCoinSelection.coinContributions.map((x) =>
+ Amounts.parseOrThrow(x),
+ ),
refreshReason: RefreshReason.PayMerchant,
});
});
@@ -1068,7 +1070,7 @@ export function selectGreedy(
wireFeesPerExchange,
wireFeeAmortization,
aci.exchangeBaseUrl,
- aci.feeDeposit,
+ Amounts.parseOrThrow(aci.feeDeposit),
);
let coinSpend = Amounts.max(
@@ -1190,8 +1192,8 @@ export async function selectPayCoinsNew(
amountPayRemaining: contractTermsAmount,
amountWireFeeLimitRemaining: wireFeeLimit,
amountDepositFeeLimitRemaining: depositFeeLimit,
- customerDepositFees: Amounts.getZero(currency),
- customerWireFees: Amounts.getZero(currency),
+ customerDepositFees: Amounts.zeroOfCurrency(currency),
+ customerWireFees: Amounts.zeroOfCurrency(currency),
wireFeeCoveredForExchange: new Set(),
};
@@ -1269,11 +1271,11 @@ export async function selectPayCoinsNew(
});
return {
- paymentAmount: contractTermsAmount,
- coinContributions,
+ paymentAmount: Amounts.stringify(contractTermsAmount),
+ coinContributions: coinContributions.map((x) => Amounts.stringify(x)),
coinPubs,
- customerDepositFees: tally.customerDepositFees,
- customerWireFees: tally.customerWireFees,
+ customerDepositFees: Amounts.stringify(tally.customerDepositFees),
+ customerWireFees: Amounts.stringify(tally.customerWireFees),
};
}
@@ -1326,10 +1328,10 @@ export async function checkPaymentByProposalId(
const res = await selectPayCoinsNew(ws, {
auditors: contractData.allowedAuditors,
exchanges: contractData.allowedExchanges,
- contractTermsAmount: contractData.amount,
- depositFeeLimit: contractData.maxDepositFee,
+ contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
+ depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
- wireFeeLimit: contractData.maxWireFee,
+ wireFeeLimit: Amounts.parseOrThrow(contractData.maxWireFee),
prevPayCoins: [],
requiredMinimumAge: contractData.minimumAge,
wireMethod: contractData.wireMethod,
@@ -1531,10 +1533,10 @@ export async function generateDepositPermissions(
denomKeyType: denom.denomPub.cipher,
denomSig: coin.denomSig,
exchangeBaseUrl: coin.exchangeBaseUrl,
- feeDeposit: denom.fees.feeDeposit,
+ feeDeposit: Amounts.parseOrThrow(denom.fees.feeDeposit),
merchantPub: contractData.merchantPub,
refundDeadline: contractData.refundDeadline,
- spendAmount: payCoinSel.coinContributions[i],
+ spendAmount: Amounts.parseOrThrow(payCoinSel.coinContributions[i]),
timestamp: contractData.timestamp,
wireInfoHash,
ageCommitmentProof: coin.ageCommitmentProof,
@@ -1684,10 +1686,10 @@ export async function confirmPay(
auditors: contractData.allowedAuditors,
exchanges: contractData.allowedExchanges,
wireMethod: contractData.wireMethod,
- contractTermsAmount: contractData.amount,
- depositFeeLimit: contractData.maxDepositFee,
+ contractTermsAmount: Amounts.parseOrThrow(contractData.amount),
+ depositFeeLimit: Amounts.parseOrThrow(contractData.maxDepositFee),
wireFeeAmortization: contractData.wireFeeAmortization ?? 1,
- wireFeeLimit: contractData.maxWireFee,
+ wireFeeLimit: Amounts.parseOrThrow(contractData.maxWireFee),
prevPayCoins: [],
requiredMinimumAge: contractData.minimumAge,
forcedSelection: forcedCoinSel,
@@ -1742,7 +1744,7 @@ export async function confirmPay(
p.payInfo = {
payCoinSelection: coinSelection,
payCoinSelectionUid: encodeCrock(getRandomBytes(16)),
- totalPayCost: payCostInfo,
+ totalPayCost: Amounts.stringify(payCostInfo),
};
p.lastSessionId = sessionId;
p.timestampAccept = TalerProtocolTimestamp.now();
@@ -1751,7 +1753,9 @@ export async function confirmPay(
await spendCoins(ws, tx, {
allocationId: `txn:proposal:${p.proposalId}`,
coinPubs: coinSelection.coinPubs,
- contributions: coinSelection.coinContributions,
+ contributions: coinSelection.coinContributions.map((x) =>
+ Amounts.parseOrThrow(x),
+ ),
refreshReason: RefreshReason.PayMerchant,
});
break;
@@ -2131,15 +2135,18 @@ async function applySuccessfulRefund(
amountLeft,
);
- refreshCoinsMap[coin.coinPub] = { coinPub: coin.coinPub, amount: amountLeft };
+ refreshCoinsMap[coin.coinPub] = {
+ coinPub: coin.coinPub,
+ amount: Amounts.stringify(amountLeft),
+ };
p.refunds[refundKey] = {
type: RefundState.Applied,
obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
executionTime: r.execution_time,
- refundAmount: Amounts.parseOrThrow(r.refund_amount),
- refundFee: denom.fees.feeRefund,
- totalRefreshCostBound,
+ refundAmount: Amounts.stringify(r.refund_amount),
+ refundFee: Amounts.stringify(denom.fees.feeRefund),
+ totalRefreshCostBound: Amounts.stringify(totalRefreshCostBound),
coinPub: r.coin_pub,
rtransactionId: r.rtransaction_id,
};
@@ -2189,9 +2196,9 @@ async function storePendingRefund(
type: RefundState.Pending,
obtainedTime: AbsoluteTime.toTimestamp(AbsoluteTime.now()),
executionTime: r.execution_time,
- refundAmount: Amounts.parseOrThrow(r.refund_amount),
- refundFee: denom.fees.feeRefund,
- totalRefreshCostBound,
+ refundAmount: Amounts.stringify(r.refund_amount),
+ refundFee: Amounts.stringify(denom.fees.feeRefund),
+ totalRefreshCostBound: Amounts.stringify(totalRefreshCostBound),
coinPub: r.coin_pub,
rtransactionId: r.rtransaction_id,
};
@@ -2241,9 +2248,9 @@ async function storeFailedRefund(
type: RefundState.Failed,
obtainedTime: TalerProtocolTimestamp.now(),
executionTime: r.execution_time,
- refundAmount: Amounts.parseOrThrow(r.refund_amount),
- refundFee: denom.fees.feeRefund,
- totalRefreshCostBound,
+ refundAmount: Amounts.stringify(r.refund_amount),
+ refundFee: Amounts.stringify(denom.fees.feeRefund),
+ totalRefreshCostBound: Amounts.stringify(totalRefreshCostBound),
coinPub: r.coin_pub,
rtransactionId: r.rtransaction_id,
};
@@ -2274,13 +2281,13 @@ async function storeFailedRefund(
let contrib: AmountJson | undefined;
for (let i = 0; i < payCoinSelection.coinPubs.length; i++) {
if (payCoinSelection.coinPubs[i] === r.coin_pub) {
- contrib = payCoinSelection.coinContributions[i];
+ contrib = Amounts.parseOrThrow(payCoinSelection.coinContributions[i]);
}
}
// FIXME: Is this case tested?!
refreshCoinsMap[coin.coinPub] = {
coinPub: coin.coinPub,
- amount: amountLeft,
+ amount: Amounts.stringify(amountLeft),
};
await tx.coins.put(coin);
}
@@ -2417,10 +2424,8 @@ async function calculateRefundSummary(
p: PurchaseRecord,
): Promise<RefundSummary> {
const download = await expectProposalDownload(ws, p);
- let amountRefundGranted = Amounts.getZero(
- download.contractData.amount.currency,
- );
- let amountRefundGone = Amounts.getZero(download.contractData.amount.currency);
+ let amountRefundGranted = Amounts.zeroOfAmount(download.contractData.amount);
+ let amountRefundGone = Amounts.zeroOfAmount(download.contractData.amount);
let pendingAtExchange = false;
@@ -2454,7 +2459,7 @@ async function calculateRefundSummary(
}
});
return {
- amountEffectivePaid: payInfo.totalPayCost,
+ amountEffectivePaid: Amounts.parseOrThrow(payInfo.totalPayCost),
amountRefundGone,
amountRefundGranted,
pendingAtExchange,
@@ -2598,7 +2603,7 @@ async function queryAndSaveAwaitingRefund(
);
if (!orderStatus.refunded) {
// Wait for retry ...
- return Amounts.getZero(download.contractData.amount.currency);
+ return Amounts.zeroOfAmount(download.contractData.amount);
}
const refundAwaiting = Amounts.sub(
@@ -2618,7 +2623,7 @@ async function queryAndSaveAwaitingRefund(
logger.warn("purchase does not exist anymore");
return;
}
- p.refundAmountAwaiting = refundAwaiting;
+ p.refundAmountAwaiting = Amounts.stringify(refundAwaiting);
await tx.purchases.put(p);
});
}
diff --git a/packages/taler-wallet-core/src/operations/pay-peer.ts b/packages/taler-wallet-core/src/operations/pay-peer.ts
index 2eb6fe20d..b6acef2dc 100644
--- a/packages/taler-wallet-core/src/operations/pay-peer.ts
+++ b/packages/taler-wallet-core/src/operations/pay-peer.ts
@@ -158,8 +158,8 @@ export async function selectPeerCoins(
}
coinInfos.push({
coinPub: coin.coinPub,
- feeDeposit: denom.feeDeposit,
- value: denom.value,
+ feeDeposit: Amounts.parseOrThrow(denom.feeDeposit),
+ value: Amounts.parseOrThrow(denom.value),
denomPubHash: denom.denomPubHash,
coinPriv: coin.coinPriv,
denomSig: coin.denomSig,
@@ -175,8 +175,8 @@ export async function selectPeerCoins(
-Amounts.cmp(o1.value, o2.value) ||
strcmp(o1.denomPubHash, o2.denomPubHash),
);
- let amountAcc = Amounts.getZero(instructedAmount.currency);
- let depositFeesAcc = Amounts.getZero(instructedAmount.currency);
+ let amountAcc = Amounts.zeroOfCurrency(instructedAmount.currency);
+ let depositFeesAcc = Amounts.zeroOfCurrency(instructedAmount.currency);
const resCoins: {
coinPub: string;
coinPriv: string;
@@ -553,7 +553,7 @@ export async function acceptPeerPushPayment(
mergeTimestamp: mergeTimestamp,
purseAmount: Amounts.stringify(amount),
purseExpiration: contractTerms.purse_expiration,
- purseFee: Amounts.stringify(Amounts.getZero(amount.currency)),
+ purseFee: Amounts.stringify(Amounts.zeroOfCurrency(amount.currency)),
pursePub: peerInc.pursePub,
reservePayto,
reservePriv: mergeReserveInfo.reservePriv,
@@ -796,7 +796,7 @@ export async function initiatePeerPullPayment(
const hContractTerms = ContractTermsUtil.hashContractTerms(contractTerms);
const purseFee = Amounts.stringify(
- Amounts.getZero(Amounts.parseOrThrow(req.amount).currency),
+ Amounts.zeroOfCurrency(Amounts.parseOrThrow(req.amount).currency),
);
const sigRes = await ws.cryptoApi.signReservePurseCreate({
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts
index e92c805bd..4feb4430d 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -291,7 +291,7 @@ async function recoupRefreshCoin(
).amount;
recoupGroup.scheduleRefreshCoins.push({
coinPub: oldCoin.coinPub,
- amount: residualAmount,
+ amount: Amounts.stringify(residualAmount),
});
}
await tx.coins.put(revokedCoin);
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index ea0fae8bb..c2f0f0360 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -110,7 +110,7 @@ export function getTotalRefreshCost(
const denomMap = Object.fromEntries(denoms.map((x) => [x.denomPubHash, x]));
const withdrawDenoms = selectWithdrawalDenominations(withdrawAmount, denoms);
const resultingAmount = Amounts.add(
- Amounts.getZero(withdrawAmount.currency),
+ Amounts.zeroOfCurrency(withdrawAmount.currency),
...withdrawDenoms.selectedDenoms.map(
(d) =>
Amounts.mult(
@@ -273,7 +273,7 @@ async function refreshCreateSession(
count: x.count,
denomPubHash: x.denomPubHash,
})),
- amountRefreshOutput: newCoinDenoms.totalCoinValue,
+ amountRefreshOutput: Amounts.stringify(newCoinDenoms.totalCoinValue),
};
await tx.refreshGroups.put(rg);
});
@@ -340,7 +340,7 @@ async function refreshMelt(
denomPub: newDenom.denomPub,
denomPubHash: newDenom.denomPubHash,
feeWithdraw: newDenom.feeWithdraw,
- value: newDenom.value,
+ value: Amounts.stringify(newDenom.value),
});
}
return { newCoinDenoms, oldCoin, oldDenom, refreshGroup, refreshSession };
@@ -368,7 +368,7 @@ async function refreshMelt(
meltCoinDenomPubHash: oldCoin.denomPubHash,
meltCoinPriv: oldCoin.coinPriv,
meltCoinPub: oldCoin.coinPub,
- feeRefresh: oldDenom.feeRefresh,
+ feeRefresh: Amounts.parseOrThrow(oldDenom.feeRefresh),
meltCoinMaxAge: oldCoin.maxAge,
meltCoinAgeCommitmentProof: oldCoin.ageCommitmentProof,
newCoinDenoms,
@@ -584,7 +584,7 @@ async function refreshReveal(
denomPub: newDenom.denomPub,
denomPubHash: newDenom.denomPubHash,
feeWithdraw: newDenom.feeWithdraw,
- value: newDenom.value,
+ value: Amounts.stringify(newDenom.value),
});
}
return {
@@ -626,7 +626,7 @@ async function refreshReveal(
meltCoinDenomPubHash: oldCoin.denomPubHash,
meltCoinPriv: oldCoin.coinPriv,
meltCoinPub: oldCoin.coinPub,
- feeRefresh: oldDenom.feeRefresh,
+ feeRefresh: Amounts.parseOrThrow(oldDenom.feeRefresh),
newCoinDenoms,
meltCoinMaxAge: oldCoin.maxAge,
meltCoinAgeCommitmentProof: oldCoin.ageCommitmentProof,
@@ -922,10 +922,14 @@ export async function createRefreshGroup(
assertUnreachable(coin.status);
}
const refreshAmount = ocp.amount;
- inputPerCoin.push(refreshAmount);
+ inputPerCoin.push(Amounts.parseOrThrow(refreshAmount));
await tx.coins.put(coin);
const denoms = await getDenoms(coin.exchangeBaseUrl);
- const cost = getTotalRefreshCost(denoms, denom, refreshAmount);
+ const cost = getTotalRefreshCost(
+ denoms,
+ denom,
+ Amounts.parseOrThrow(refreshAmount),
+ );
const output = Amounts.sub(refreshAmount, cost).amount;
estimatedOutputPerCoin.push(output);
}
@@ -934,13 +938,15 @@ export async function createRefreshGroup(
operationStatus: RefreshOperationStatus.Pending,
timestampFinished: undefined,
statusPerCoin: oldCoinPubs.map(() => RefreshCoinStatus.Pending),
- lastErrorPerCoin: {},
oldCoinPubs: oldCoinPubs.map((x) => x.coinPub),
+ lastErrorPerCoin: {},
reason,
refreshGroupId,
refreshSessionPerCoin: oldCoinPubs.map(() => undefined),
- inputPerCoin,
- estimatedOutputPerCoin,
+ inputPerCoin: inputPerCoin.map((x) => Amounts.stringify(x)),
+ estimatedOutputPerCoin: estimatedOutputPerCoin.map((x) =>
+ Amounts.stringify(x),
+ ),
timestampCreated: TalerProtocolTimestamp.now(),
};
@@ -1037,11 +1043,11 @@ export async function autoRefresh(
if (AbsoluteTime.isExpired(executeThreshold)) {
refreshCoins.push({
coinPub: coin.coinPub,
- amount: {
+ amount: Amounts.stringify({
value: denom.amountVal,
fraction: denom.amountFrac,
currency: denom.currency,
- },
+ }),
});
} else {
const checkThreshold = getAutoRefreshCheckThreshold(denom);
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts
index f98d69e26..f9d20fa03 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -127,13 +127,13 @@ export async function prepareTip(
const newTipRecord: TipRecord = {
walletTipId: walletTipId,
acceptedTimestamp: undefined,
- tipAmountRaw: amount,
+ tipAmountRaw: Amounts.stringify(amount),
tipExpiration: tipPickupStatus.expiration,
exchangeBaseUrl: tipPickupStatus.exchange_url,
merchantBaseUrl: res.merchantBaseUrl,
createdTimestamp: TalerProtocolTimestamp.now(),
merchantTipId: res.merchantTipId,
- tipAmountEffective: selectedDenoms.totalCoinValue,
+ tipAmountEffective: Amounts.stringify(selectedDenoms.totalCoinValue),
denomsSel: selectedDenoms,
pickedUpTimestamp: undefined,
secretSeed,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 54cb84926..fd0a343e5 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -26,6 +26,7 @@ import {
Logger,
OrderShortInfo,
PaymentStatus,
+ PeerContractTerms,
RefundInfoShort,
TalerProtocolTimestamp,
Transaction,
@@ -49,6 +50,8 @@ import {
WithdrawalGroupRecord,
WithdrawalRecordType,
WalletContractData,
+ PeerPushPaymentInitiationStatus,
+ PeerPullPaymentIncomingStatus,
} from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { assertUnreachable } from "../util/assertUnreachable.js";
@@ -222,7 +225,7 @@ export async function getTransactionById(
const contractData = download.contractData;
const refunds = mergeRefundByExecutionTime(
cleanRefunds,
- Amounts.getZero(contractData.amount.currency),
+ Amounts.zeroOfAmount(contractData.amount),
);
const payOpId = RetryTags.forPay(purchase);
@@ -296,7 +299,7 @@ export async function getTransactionById(
const contractData = download.contractData;
const refunds = mergeRefundByExecutionTime(
[theRefund],
- Amounts.getZero(contractData.amount.currency),
+ Amounts.zeroOfAmount(contractData.amount),
);
return buildTransactionForRefund(
@@ -320,11 +323,13 @@ export async function getTransactionById(
} else if (type === TransactionType.PeerPushDebit) {
const pursePub = rest[0];
return await ws.db
- .mktx((x) => [x.peerPushPaymentInitiations])
+ .mktx((x) => [x.peerPushPaymentInitiations, x.contractTerms])
.runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub);
if (!debit) throw Error("not found");
- return buildTransactionForPushPaymentDebit(debit);
+ const ct = await tx.contractTerms.get(debit.contractTermsHash);
+ checkDbInvariant(!!ct);
+ return buildTransactionForPushPaymentDebit(debit, ct.contractTermsRaw);
});
} else {
const unknownTxType: never = type;
@@ -334,6 +339,7 @@ export async function getTransactionById(
function buildTransactionForPushPaymentDebit(
pi: PeerPushPaymentInitiationRecord,
+ contractTerms: PeerContractTerms,
ort?: OperationRetryRecord,
): Transaction {
return {
@@ -342,11 +348,11 @@ function buildTransactionForPushPaymentDebit(
amountRaw: pi.amount,
exchangeBaseUrl: pi.exchangeBaseUrl,
info: {
- expiration: pi.contractTerms.purse_expiration,
- summary: pi.contractTerms.summary,
+ expiration: contractTerms.purse_expiration,
+ summary: contractTerms.summary,
},
frozen: false,
- pending: !pi.purseCreated,
+ pending: pi.status != PeerPushPaymentInitiationStatus.PurseCreated,
timestamp: pi.timestampCreated,
talerUri: constructPayPushUri({
exchangeBaseUrl: pi.exchangeBaseUrl,
@@ -586,7 +592,7 @@ function mergeRefundByExecutionTime(
prev.set(key, {
executionTime: refund.executionTime,
amountAppliedEffective: effective,
- amountAppliedRaw: raw,
+ amountAppliedRaw: Amounts.parseOrThrow(raw),
firstTimestamp: refund.obtainedTime,
});
} else {
@@ -659,7 +665,7 @@ async function buildTransactionForPurchase(
refundsInfo: MergedRefundInfo[],
ort?: OperationRetryRecord,
): Promise<Transaction> {
- const zero = Amounts.getZero(contractData.amount.currency);
+ const zero = Amounts.zeroOfAmount(contractData.amount);
const info: OrderShortInfo = {
merchant: contractData.merchant,
@@ -769,7 +775,11 @@ export async function getTransactions(
if (shouldSkipSearch(transactionsRequest, [])) {
return;
}
- transactions.push(buildTransactionForPushPaymentDebit(pi));
+ const ct = await tx.contractTerms.get(pi.contractTermsHash);
+ checkDbInvariant(!!ct);
+ transactions.push(
+ buildTransactionForPushPaymentDebit(pi, ct.contractTermsRaw),
+ );
});
tx.peerPullPaymentIncoming.iter().forEachAsync(async (pi) => {
@@ -780,7 +790,10 @@ export async function getTransactions(
if (shouldSkipSearch(transactionsRequest, [])) {
return;
}
- if (!pi.accepted) {
+ if (
+ pi.status !== PeerPullPaymentIncomingStatus.Accepted &&
+ pi.status !== PeerPullPaymentIncomingStatus.Paid
+ ) {
return;
}
@@ -791,7 +804,7 @@ export async function getTransactions(
if (
shouldSkipCurrency(
transactionsRequest,
- wsr.rawWithdrawalAmount.currency,
+ Amounts.currencyOf(wsr.rawWithdrawalAmount),
)
) {
return;
@@ -899,7 +912,7 @@ export async function getTransactions(
const refunds = mergeRefundByExecutionTime(
cleanRefunds,
- Amounts.getZero(download.currency),
+ Amounts.zeroOfCurrency(download.currency),
);
refunds.forEach(async (refundInfo) => {
@@ -929,7 +942,7 @@ export async function getTransactions(
if (
shouldSkipCurrency(
transactionsRequest,
- tipRecord.tipAmountRaw.currency,
+ Amounts.parseOrThrow(tipRecord.tipAmountRaw).currency,
)
) {
return;
diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts
index 70b4f73c0..c77f75b9d 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.test.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts
@@ -39,26 +39,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
@@ -95,26 +95,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
@@ -150,26 +150,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
@@ -206,26 +206,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
@@ -261,26 +261,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
@@ -316,26 +316,26 @@ test("withdrawal selection bug repro", (t) => {
exchangeBaseUrl: "https://exchange.demo.taler.net/",
exchangeMasterPub: "",
fees: {
- feeDeposit: {
+ feeDeposit: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefresh: {
+ }),
+ feeRefresh: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeRefund: {
+ }),
+ feeRefund: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
- feeWithdraw: {
+ }),
+ feeWithdraw: Amounts.stringify({
currency: "KUDOS",
fraction: 1000000,
value: 0,
- },
+ }),
},
isOffered: true,
isRevoked: false,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index a9ecdf369..76bbec416 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -167,8 +167,8 @@ export function selectWithdrawalDenominations(
denomPubHash: string;
}[] = [];
- let totalCoinValue = Amounts.getZero(amountAvailable.currency);
- let totalWithdrawCost = Amounts.getZero(amountAvailable.currency);
+ let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
+ let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
denoms = denoms.filter(isWithdrawableDenom);
denoms.sort((d1, d2) =>
@@ -223,8 +223,8 @@ export function selectWithdrawalDenominations(
return {
selectedDenoms,
- totalCoinValue,
- totalWithdrawCost,
+ totalCoinValue: Amounts.stringify(totalCoinValue),
+ totalWithdrawCost: Amounts.stringify(totalCoinValue),
};
}
@@ -238,8 +238,8 @@ export function selectForcedWithdrawalDenominations(
denomPubHash: string;
}[] = [];
- let totalCoinValue = Amounts.getZero(amountAvailable.currency);
- let totalWithdrawCost = Amounts.getZero(amountAvailable.currency);
+ let totalCoinValue = Amounts.zeroOfCurrency(amountAvailable.currency);
+ let totalWithdrawCost = Amounts.zeroOfCurrency(amountAvailable.currency);
denoms = denoms.filter(isWithdrawableDenom);
denoms.sort((d1, d2) =>
@@ -279,8 +279,8 @@ export function selectForcedWithdrawalDenominations(
return {
selectedDenoms,
- totalCoinValue,
- totalWithdrawCost,
+ totalCoinValue: Amounts.stringify(totalCoinValue),
+ totalWithdrawCost: Amounts.stringify(totalWithdrawCost),
};
}
@@ -416,10 +416,10 @@ async function processPlanchetGenerate(
checkDbInvariant(!!denom);
const r = await ws.cryptoApi.createPlanchet({
denomPub: denom.denomPub,
- feeWithdraw: denom.feeWithdraw,
+ feeWithdraw: Amounts.parseOrThrow(denom.feeWithdraw),
reservePriv: withdrawalGroup.reservePriv,
reservePub: withdrawalGroup.reservePub,
- value: denom.value,
+ value: Amounts.parseOrThrow(denom.value),
coinIndex: coinIdx,
secretSeed: withdrawalGroup.secretSeed,
restrictAge: withdrawalGroup.restrictAge,
@@ -950,7 +950,7 @@ async function queryReserve(
return;
}
wg.status = WithdrawalGroupStatus.Ready;
- wg.reserveBalanceAmount = Amounts.parse(result.response.balance);
+ wg.reserveBalanceAmount = Amounts.stringify(result.response.balance);
await tx.withdrawalGroups.put(wg);
});
@@ -1427,7 +1427,7 @@ export async function getFundingPaytoUrisTx(
export function augmentPaytoUrisForWithdrawal(
plainPaytoUris: string[],
reservePub: string,
- instructedAmount: AmountJson,
+ instructedAmount: AmountLike,
): string[] {
return plainPaytoUris.map((x) =>
addPaytoQueryParams(x, {
@@ -1732,7 +1732,7 @@ export async function internalCreateWithdrawalGroup(
denomSelUid,
denomsSel: initialDenomSel,
exchangeBaseUrl: canonExchange,
- instructedAmount: amount,
+ instructedAmount: Amounts.stringify(amount),
timestampStart: now,
rawWithdrawalAmount: initialDenomSel.totalWithdrawCost,
effectiveWithdrawalAmount: initialDenomSel.totalCoinValue,
diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts
index 12f87a920..cadf8d829 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.ts
@@ -139,7 +139,7 @@ export function tallyFees(
if (!tally.wireFeeCoveredForExchange.has(exchangeBaseUrl)) {
const wf =
- wireFeesPerExchange[exchangeBaseUrl] ?? Amounts.getZero(currency);
+ wireFeesPerExchange[exchangeBaseUrl] ?? Amounts.zeroOfCurrency(currency);
const wfForgiven = Amounts.min(amountWireFeeLimitRemaining, wf);
amountWireFeeLimitRemaining = Amounts.sub(
amountWireFeeLimitRemaining,
diff --git a/packages/taler-wallet-core/src/util/denominations.test.ts b/packages/taler-wallet-core/src/util/denominations.test.ts
index 9c93331a3..551e06a33 100644
--- a/packages/taler-wallet-core/src/util/denominations.test.ts
+++ b/packages/taler-wallet-core/src/util/denominations.test.ts
@@ -25,6 +25,7 @@ import {
FeeDescriptionPair,
Amounts,
DenominationInfo,
+ AmountString,
} from "@gnu-taler/taler-util";
// import { expect } from "chai";
import {
@@ -37,8 +38,8 @@ import test, { ExecutionContext } from "ava";
/**
* Create some constants to be used as reference in the tests
*/
-const VALUES = Array.from({ length: 10 }).map((undef, t) =>
- Amounts.parseOrThrow(`USD:${t}`),
+const VALUES: AmountString[] = Array.from({ length: 10 }).map(
+ (undef, t) => `USD:${t}`,
);
const TIMESTAMPS = Array.from({ length: 20 }).map((undef, t_s) => ({ t_s }));
const ABS_TIME = TIMESTAMPS.map((m) => AbsoluteTime.fromTimestamp(m));
diff --git a/packages/taler-wallet-core/src/util/denominations.ts b/packages/taler-wallet-core/src/util/denominations.ts
index 9cd931acd..c05df6c6e 100644
--- a/packages/taler-wallet-core/src/util/denominations.ts
+++ b/packages/taler-wallet-core/src/util/denominations.ts
@@ -18,6 +18,7 @@ import {
AbsoluteTime,
AmountJson,
Amounts,
+ AmountString,
DenominationInfo,
FeeDescription,
FeeDescriptionPair,
@@ -51,7 +52,7 @@ export function selectBestForOverlappingDenominations<
return minDeposit;
}
-export function selectMinimumFee<T extends { fee: AmountJson }>(
+export function selectMinimumFee<T extends { fee: AmountString }>(
list: T[],
): T | undefined {
let minFee: T | undefined = undefined;
@@ -285,7 +286,7 @@ export function createTimeline<Type extends object>(
idProp: PropsWithReturnType<Type, string>,
periodStartProp: PropsWithReturnType<Type, TalerProtocolTimestamp>,
periodEndProp: PropsWithReturnType<Type, TalerProtocolTimestamp>,
- feeProp: PropsWithReturnType<Type, AmountJson>,
+ feeProp: PropsWithReturnType<Type, AmountString>,
groupProp: PropsWithReturnType<Type, string> | undefined,
selectBestForOverlapping: (l: Type[]) => Type | undefined,
): FeeDescription[] {
@@ -312,7 +313,7 @@ export function createTimeline<Type extends object>(
}
ps.push({
type: "start",
- fee,
+ fee: Amounts.stringify(fee),
group,
id,
moment: AbsoluteTime.fromTimestamp(stampStart),
@@ -320,7 +321,7 @@ export function createTimeline<Type extends object>(
});
ps.push({
type: "end",
- fee,
+ fee: Amounts.stringify(fee),
group,
id,
moment: AbsoluteTime.fromTimestamp(stampEnd),
@@ -416,7 +417,7 @@ export function createTimeline<Type extends object>(
group: cursor.group,
from: cursor.moment,
until: AbsoluteTime.never(), //not yet known
- fee: currentFee,
+ fee: Amounts.stringify(currentFee),
});
} else {
prev.until = cursor.moment;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index f800b68f8..9339b2f8e 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -771,7 +771,7 @@ async function getExchangeDetailedInfo(
const feesByGroup = [
...infoForType.map((w) => ({
...w,
- fee: w.closingFee,
+ fee: Amounts.stringify(w.closingFee),
group: "closing",
})),
...infoForType.map((w) => ({ ...w, fee: w.wireFee, group: "wire" })),
diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
index 6f71b9d2e..1396d8707 100644
--- a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
@@ -33,11 +33,7 @@ export default {
};
const cd: WalletContractData = {
- amount: {
- currency: "ARS",
- fraction: 0,
- value: 2,
- },
+ amount: "ARS:2",
contractTermsHash:
"92X0KSJPZ8XS2XECCGFWTCGW8XMFCXTT2S6WHZDP6H9Y3TSKMTHY94WXEWDERTNN5XWCYGW4VN5CF2D4846HXTW7P06J4CZMHCWKC9G",
fulfillmentUrl: "",
@@ -47,11 +43,7 @@ const cd: WalletContractData = {
"0YA1WETV15R6K8QKS79QA3QMT16010F42Q49VSKYQ71HVQKAG0A4ZJCA4YTKHE9EA5SP156TJSKZEJJJ87305N6PS80PC48RNKYZE08",
orderId: "2022.220-0281XKKB8W7YE",
summary: "w",
- maxWireFee: {
- currency: "ARS",
- fraction: 0,
- value: 1,
- },
+ maxWireFee: "ARS:1",
payDeadline: {
t_s: 1660002673,
},
@@ -77,11 +69,7 @@ const cd: WalletContractData = {
wireMethod: "x-taler-bank",
wireInfoHash:
"QDT28374ZHYJ59WQFZ3TW1D5WKJVDYHQT86VHED3TNMB15ANJSKXDYPPNX01348KDYCX6T4WXA5A8FJJ8YWNEB1JW726C1JPKHM89DR",
- maxDepositFee: {
- currency: "ARS",
- fraction: 0,
- value: 1,
- },
+ maxDepositFee: "ARS:1",
merchant: {
name: "Default",
address: {
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index a70682d89..2693db79e 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -99,7 +99,7 @@ export function useComponentState(
const balance =
bs.length > 0
? Amounts.parseOrThrow(bs[0].available)
- : Amounts.getZero(currency);
+ : Amounts.zeroOfCurrency(currency);
if (Amounts.isZero(balance)) {
return {
@@ -157,12 +157,12 @@ export function useComponentState(
const totalFee =
fee !== undefined
? Amounts.sum([fee.wire, fee.coin, fee.refresh]).amount
- : Amounts.getZero(currency);
+ : Amounts.zeroOfCurrency(currency);
const totalToDeposit =
parsedAmount && fee !== undefined
? Amounts.sub(parsedAmount, totalFee).amount
- : Amounts.getZero(currency);
+ : Amounts.zeroOfCurrency(currency);
const isDirty = amount !== initialValue;
const amountError = !isDirty
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx b/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
index 64b2c91a7..af9c620cb 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/stories.tsx
@@ -76,7 +76,7 @@ export const WithNoAccountForIBAN = createExample(ReadyView, {
return;
},
},
- totalFee: Amounts.getZero("USD"),
+ totalFee: Amounts.zeroOfCurrency("USD"),
totalToDeposit: Amounts.parseOrThrow("USD:10"),
// onCalculateFee: alwaysReturnFeeToOne,
});
@@ -111,7 +111,7 @@ export const WithIBANAccountTypeSelected = createExample(ReadyView, {
return;
},
},
- totalFee: Amounts.getZero("USD"),
+ totalFee: Amounts.zeroOfCurrency("USD"),
totalToDeposit: Amounts.parseOrThrow("USD:10"),
// onCalculateFee: alwaysReturnFeeToOne,
});
@@ -146,7 +146,7 @@ export const NewBitcoinAccountTypeSelected = createExample(ReadyView, {
return;
},
},
- totalFee: Amounts.getZero("USD"),
+ totalFee: Amounts.zeroOfCurrency("USD"),
totalToDeposit: Amounts.parseOrThrow("USD:10"),
// onCalculateFee: alwaysReturnFeeToOne,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index d7b6e3b1c..9fff76442 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -1132,7 +1132,7 @@ export function PurchaseDetails({
const partialFee = Amounts.sub(price.effective, price.raw).amount;
const refundFee = !refund
- ? Amounts.getZero(price.effective.currency)
+ ? Amounts.zeroOfCurrency(price.effective.currency)
: Amounts.sub(refund.raw, refund.effective).amount;
const fee = Amounts.sum([partialFee, refundFee]).amount;