commit 0cd959846389205711dfab9a871d96d573c494cb
parent 99a259a3ebf14c9130b858b3ccbff222331cdacb
Author: Florian Dold <florian@dold.me>
Date: Wed, 26 Feb 2025 17:01:22 +0100
clean up some types
Diffstat:
8 files changed, 213 insertions(+), 161 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/hooks/officer.ts b/packages/aml-backoffice-ui/src/hooks/officer.ts
@@ -16,11 +16,11 @@
import {
AbsoluteTime,
Codec,
+ EddsaPrivP,
LockedAccount,
OfficerAccount,
OfficerId,
OperationOk,
- SigningKey,
buildCodecForObject,
codecForAbsoluteTime,
codecForString,
@@ -99,7 +99,7 @@ export function useOfficer(): OfficerState {
return {
id: accountStorage.value.id as OfficerId,
- signingKey: decodeCrock(accountStorage.value.strKey) as SigningKey,
+ signingKey: decodeCrock(accountStorage.value.strKey) as EddsaPrivP,
};
}, [accountStorage.value?.id, accountStorage.value?.strKey]);
diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts
@@ -35,20 +35,13 @@ import {
opSuccessFromHttp,
opUnknownFailure,
} from "../operation.js";
-import {
- TalerSignaturePurpose,
- amountToBuffer,
- buildSigPS,
- eddsaSign,
- encodeCrock,
-} from "../taler-crypto.js";
+import { EddsaPrivP, encodeCrock } from "../taler-crypto.js";
import {
AccessToken,
AmountString,
OfficerAccount,
PaginationParams,
ReserveAccount,
- SigningKey,
codecForTalerCommonConfigResponse,
} from "../types-taler-common.js";
import {
@@ -74,7 +67,14 @@ import {
import { CacheEvictor, addPaginationParams, nullEvictor } from "./utils.js";
import { TalerError } from "../errors.js";
-import { AmountJson, Amounts, signAmlDecision } from "../index.js";
+import {
+ AmountJson,
+ Amounts,
+ signKycAuth,
+ signWalletAccountSetup,
+ signAmlDecision,
+ signAmlQuery,
+} from "../index.js";
import { TalerErrorCode } from "../taler-error-codes.js";
import { AbsoluteTime } from "../time.js";
import { codecForEmptyObject } from "../types-taler-wallet.js";
@@ -614,7 +614,9 @@ export class TalerExchangeHttpClient {
const body: WalletKycRequest = {
balance,
reserve_pub: account.id,
- reserve_sig: buildKYCWalletBalanceSignature(account.signingKey, balance),
+ reserve_sig: encodeCrock(
+ signWalletAccountSetup(account.signingKey, balance),
+ ),
};
const resp = await this.httpLib.fetch(url.href, {
@@ -645,7 +647,7 @@ export class TalerExchangeHttpClient {
*
*/
async checkKycStatus(
- signingKey: SigningKey,
+ signingKey: EddsaPrivP,
paytoHash: string,
params: {
timeout?: number;
@@ -664,7 +666,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Account-Owner-Signature": buildKYCQuerySignature(signingKey),
+ "Account-Owner-Signature": encodeCrock(
+ signKycAuth(signingKey),
+ ),
},
});
@@ -834,7 +838,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
@@ -876,7 +882,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
switch (resp.status) {
@@ -924,7 +932,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
@@ -959,7 +969,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
@@ -996,7 +1008,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
body,
});
@@ -1038,7 +1052,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
@@ -1077,7 +1093,9 @@ export class TalerExchangeHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "GET",
headers: {
- "Taler-AML-Officer-Signature": buildAMLQuerySignature(auth.signingKey),
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.signingKey),
+ ),
},
});
@@ -1139,26 +1157,3 @@ export class TalerExchangeHttpClient {
throw Error("not yet implemented");
}
}
-
-function buildKYCWalletBalanceSignature(
- key: SigningKey,
- balance: AmountString,
-): string {
- const sigBlob = buildSigPS(TalerSignaturePurpose.WALLET_ACCOUNT_SETUP)
- .put(amountToBuffer(balance))
- .build();
-
- return encodeCrock(eddsaSign(sigBlob, key));
-}
-
-function buildKYCQuerySignature(key: SigningKey): string {
- const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
-
- return encodeCrock(eddsaSign(sigBlob, key));
-}
-
-function buildAMLQuerySignature(key: SigningKey): string {
- const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build();
-
- return encodeCrock(eddsaSign(sigBlob, key));
-}
diff --git a/packages/taler-util/src/http-client/officer-account.ts b/packages/taler-util/src/http-client/officer-account.ts
@@ -15,20 +15,20 @@
*/
import {
- EncryptionNonce,
+ EddsaPrivP,
+ EncryptionNonceP,
LockedAccount,
OfficerAccount,
OfficerId,
ReserveAccount,
ReservePub,
- SigningKey,
createEddsaKeyPair,
decodeCrock,
decryptWithDerivedKey,
eddsaGetPublic,
encodeCrock,
encryptWithDerivedKey,
- getRandomBytesF,
+ getRandomBytes,
kdf,
stringToBytes
} from "@gnu-taler/taler-util";
@@ -54,7 +54,7 @@ export async function unlockOfficerAccount(
password,
).catch((e) => {
throw new UnwrapKeyError(e instanceof Error ? e.message : String(e));
- })) as SigningKey;
+ })) as EddsaPrivP;
const publicKey = eddsaGetPublic(signingKey);
@@ -73,14 +73,14 @@ export async function unlockOfficerAccount(
*/
export async function createNewOfficerAccount(
password: string,
- extraNonce: EncryptionNonce,
+ extraNonce: EncryptionNonceP,
): Promise<OfficerAccount & { safe: LockedAccount }> {
const { eddsaPriv, eddsaPub } = createEddsaKeyPair();
const key = stringToBytes(password);
- const localRnd = getRandomBytesF(24);
- const mergedRnd: EncryptionNonce = extraNonce
+ const localRnd = getRandomBytes(24);
+ const mergedRnd: EncryptionNonceP = extraNonce
? kdf(24, stringToBytes("aml-officer"), extraNonce, localRnd)
: localRnd;
@@ -91,7 +91,7 @@ export async function createNewOfficerAccount(
password,
);
- const signingKey = eddsaPriv as SigningKey;
+ const signingKey = eddsaPriv as EddsaPrivP;
const accountId = encodeCrock(eddsaPub) as OfficerId;
const safe = encodeCrock(protectedPrivKey) as LockedAccount;
@@ -107,14 +107,14 @@ export async function createNewOfficerAccount(
* @returns
*/
export async function createNewWalletKycAccount(
- extraNonce: EncryptionNonce,
+ extraNonce: EncryptionNonceP,
password?: string,
): Promise<ReserveAccount & { safe?: LockedAccount }> {
const { eddsaPriv, eddsaPub } = createEddsaKeyPair();
- const mergedRnd: EncryptionNonce = extraNonce && password
- ? kdf(24, stringToBytes("aml-officer"), extraNonce, getRandomBytesF(24))
- : getRandomBytesF(24);
+ const mergedRnd: EncryptionNonceP = extraNonce && password
+ ? kdf(24, stringToBytes("aml-officer"), extraNonce, getRandomBytes(24))
+ : getRandomBytes(24);
const protectedPrivKey = password ? await encryptWithDerivedKey(
@@ -124,7 +124,7 @@ export async function createNewWalletKycAccount(
password,
) : undefined;
- const signingKey = eddsaPriv as SigningKey;
+ const signingKey = eddsaPriv as EddsaPrivP;
const accountId = encodeCrock(eddsaPub) as ReservePub;
const safe = protectedPrivKey ? encodeCrock(protectedPrivKey) as LockedAccount : undefined;
diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts
@@ -38,22 +38,89 @@ import {
DenominationPubKey,
} from "./types-taler-exchange.js";
-export type Flavor<T, FlavorT extends string> = T & {
- _flavor?: `taler.${FlavorT}`;
+const isEddsaPubP: unique symbol = Symbol("isEddsaPubP");
+type FlavorEddsaPubP = {
+ readonly flavor?: typeof isEddsaPubP;
+ readonly _size?: 32;
};
-export type FlavorP<T, FlavorT extends string, S extends number> = T & {
- _flavor?: `taler.${FlavorT}`;
- _size?: S;
+const isEddsaPrivP: unique symbol = Symbol("isEddsaPrivP");
+type FlavorEddsaPrivP = {
+ readonly flavor?: typeof isEddsaPrivP;
+ readonly _size?: 32;
};
-export function getRandomBytes(n: number): Uint8Array {
- return nacl.randomBytes(n);
-}
+const isEddsaSigP: unique symbol = Symbol("isEddsaSigP");
+type FlavorEddsaSigP = {
+ readonly flavor?: typeof isEddsaSigP;
+ readonly _size?: 64;
+};
+
+const isEdx25519PublicKey: unique symbol = Symbol("isEdx25519PublicKey");
+type FlavorEdx25519PublicKey = {
+ readonly flavor?: typeof isEdx25519PublicKey;
+ readonly _size?: 32;
+};
+
+const isEdx25519PrivateKey: unique symbol = Symbol("isEdx25519PrivateKey");
+type FlavorEdx25519PrivateKey = {
+ readonly flavor?: typeof isEdx25519PrivateKey;
+ readonly _size?: 64;
+};
+
+const isEcdhePrivP: unique symbol = Symbol("isEcdhePrivP");
+type FlavorEcdhePrivP = {
+ readonly flavor?: typeof isEcdhePrivP;
+ readonly _size?: 32;
+};
+
+const isEdx25519Signature: unique symbol = Symbol("isEdx25519Signature");
+type FlavorEdx25519Signature = {
+ readonly flavor?: typeof isEdx25519Signature;
+ readonly _size?: 64;
+};
+
+const isEdx25519PublicKeyEnc: unique symbol = Symbol("isEdx25519PublicKeyEnc");
+type FlavorEdx25519PublicKeyEnc = {
+ readonly [isEdx25519PublicKeyEnc]?: true;
+};
+
+const isEdx25519PrivateKeyEnc: unique symbol = Symbol(
+ "isEdx25519PrivateKeyEnc",
+);
+type FlavorEdx25519PrivateKeyEnc = {
+ readonly [isEdx25519PrivateKeyEnc]?: true;
+};
+
+const isEncryptionNonce: unique symbol = Symbol("isEncryptionNone");
+type FlavorEncryptionNonceP = {
+ readonly flavor?: typeof isEncryptionNonce;
+};
+
+type Sized<T> = { readonly _size?: T };
+
+export type EddsaPubP = Uint8Array & FlavorEddsaPubP;
+export type EddsaPrivP = Uint8Array & FlavorEddsaPrivP;
+export type EddsaSigP = Uint8Array & FlavorEddsaSigP;
+
+export type EcdhePrivP = Uint8Array & FlavorEcdhePrivP;
-export function getRandomBytesF<T extends number, N extends string>(
- n: T,
-): FlavorP<Uint8Array, N, T> {
+export type OpaqueData = Uint8Array;
+export type Edx25519PublicKey = Uint8Array & FlavorEdx25519PublicKey;
+export type Edx25519PrivateKey = Uint8Array & FlavorEdx25519PrivateKey;
+export type Edx25519Signature = Uint8Array & FlavorEdx25519Signature;
+
+export type Edx25519PublicKeyEnc = string & FlavorEdx25519PublicKeyEnc;
+export type Edx25519PrivateKeyEnc = string & FlavorEdx25519PrivateKeyEnc;
+
+export type EncryptionNonceP = Uint8Array & FlavorEncryptionNonceP;
+
+export type PursePublicKey = EddsaPubP;
+
+export type ContractPrivateKey = EcdhePrivP;
+export type MergePrivateKeyP = Uint8Array & EddsaPrivP;
+
+export function getRandomBytes<N extends number>(n: N): Uint8Array & Sized<N> {
return nacl.randomBytes(n);
}
@@ -317,8 +384,8 @@ export function keyExchangeEddsaEcdh(
}
export function keyExchangeEcdhEddsa(
- ecdhPriv: Uint8Array & MaterialEcdhePriv,
- eddsaPub: Uint8Array & MaterialEddsaPub,
+ ecdhPriv: Uint8Array & FlavorEcdhePrivP,
+ eddsaPub: Uint8Array & FlavorEddsaPubP,
): Uint8Array {
if (tart) {
return tart.keyExchangeEcdhEddsa(ecdhPriv, eddsaPub);
@@ -1056,18 +1123,6 @@ export function buildSigPS(purposeNum: number): SignaturePurposeBuilder {
return new SignaturePurposeBuilder(purposeNum);
}
-export type OpaqueData = Flavor<Uint8Array, any>;
-export type Edx25519PublicKey = FlavorP<Uint8Array, "Edx25519PublicKey", 32>;
-export type Edx25519PrivateKey = FlavorP<Uint8Array, "Edx25519PrivateKey", 64>;
-export type Edx25519Signature = FlavorP<Uint8Array, "Edx25519Signature", 64>;
-
-export type Edx25519PublicKeyEnc = FlavorP<string, "Edx25519PublicKeyEnc", 32>;
-export type Edx25519PrivateKeyEnc = FlavorP<
- string,
- "Edx25519PrivateKeyEnc",
- 64
->;
-
/**
* Convert a big integer to a fixed-size, little-endian array.
*/
@@ -1436,12 +1491,9 @@ export namespace AgeRestriction {
}
}
-// FIXME: make it a branded type!
-export type EncryptionNonce = FlavorP<Uint8Array, "EncryptionNonce", 24>;
-
async function deriveKey(
keySeed: OpaqueData,
- nonce: EncryptionNonce,
+ nonce: EncryptionNonceP,
salt: string,
): Promise<Uint8Array> {
return kdfKw({
@@ -1453,7 +1505,7 @@ async function deriveKey(
}
export async function encryptWithDerivedKey(
- nonce: EncryptionNonce,
+ nonce: EncryptionNonceP,
keySeed: OpaqueData,
plaintext: OpaqueData,
salt: string,
@@ -1486,44 +1538,15 @@ enum ContractFormatTag {
PaymentRequest = 1,
}
-type MaterialEddsaPub = {
- _materialType?: "eddsa-pub";
- _size?: 32;
-};
-
-type MaterialEddsaPriv = {
- _materialType?: "ecdhe-priv";
- _size?: 32;
-};
-
-type MaterialEcdhePub = {
- _materialType?: "ecdhe-pub";
- _size?: 32;
-};
-
-type MaterialEcdhePriv = {
- _materialType?: "ecdhe-priv";
- _size?: 32;
-};
-
-type PursePublicKey = FlavorP<Uint8Array, "PursePublicKey", 32> &
- MaterialEddsaPub;
-
-type ContractPrivateKey = FlavorP<Uint8Array, "ContractPrivateKey", 32> &
- MaterialEcdhePriv;
-
-type MergePrivateKey = FlavorP<Uint8Array, "MergePrivateKey", 32> &
- MaterialEddsaPriv;
-
const mergeSalt = "p2p-merge-contract";
const depositSalt = "p2p-deposit-contract";
export function encryptContractForMerge(
pursePub: PursePublicKey,
contractPriv: ContractPrivateKey,
- mergePriv: MergePrivateKey,
+ mergePriv: MergePrivateKeyP,
contractTerms: any,
- nonce: EncryptionNonce,
+ nonce: EncryptionNonceP,
): Promise<OpaqueData> {
const contractTermsCanon = canonicalJson(contractTerms) + "\0";
const contractTermsBytes = stringToBytes(contractTermsCanon);
@@ -1542,7 +1565,7 @@ export function encryptContractForDeposit(
pursePub: PursePublicKey,
contractPriv: ContractPrivateKey,
contractTerms: any,
- nonce: EncryptionNonce,
+ nonce: EncryptionNonceP,
): Promise<OpaqueData> {
const contractTermsCanon = canonicalJson(contractTerms) + "\0";
const contractTermsBytes = stringToBytes(contractTermsCanon);
diff --git a/packages/taler-util/src/taler-signatures.ts b/packages/taler-util/src/taler-signatures.ts
@@ -14,12 +14,15 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { canonicalJson, TalerProtocolTimestamp } from "./index.js";
+import { AmountLike, canonicalJson, TalerProtocolTimestamp } from "./index.js";
import {
+ amountToBuffer,
bufferForUint64,
buildSigPS,
decodeCrock,
+ EddsaPrivP,
eddsaSign,
+ EddsaSigP,
hash,
stringToBytes,
TalerSignaturePurpose,
@@ -72,8 +75,25 @@ export function signAmlDecision(
return eddsaSign(sigBlob, priv);
}
-export function signAmlQuery(key: Uint8Array): Uint8Array {
+export function signAmlQuery(key: Uint8Array): EddsaSigP {
const sigBlob = buildSigPS(TalerSignaturePurpose.AML_QUERY).build();
return eddsaSign(sigBlob, key);
}
+
+export function signWalletAccountSetup(
+ key: EddsaPrivP,
+ balance: AmountLike,
+): EddsaSigP {
+ const sigBlob = buildSigPS(TalerSignaturePurpose.WALLET_ACCOUNT_SETUP)
+ .put(amountToBuffer(balance))
+ .build();
+
+ return eddsaSign(sigBlob, key);
+}
+
+export function signKycAuth(key: EddsaPrivP): EddsaSigP {
+ const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
+
+ return eddsaSign(sigBlob, key);
+}
diff --git a/packages/taler-util/src/types-taler-common.ts b/packages/taler-util/src/types-taler-common.ts
@@ -38,7 +38,7 @@ import {
codecForNumber,
codecForString,
} from "./codec.js";
-import { ReservePub } from "./index.js";
+import { EddsaPrivP, ReservePub } from "./index.js";
import {
TalerProtocolDuration,
TalerProtocolTimestamp,
@@ -481,19 +481,15 @@ declare const opaque_OfficerId: unique symbol;
export type OfficerId = string & { [opaque_OfficerId]: true };
declare const opaque_OfficerSigningKey: unique symbol;
-/**
- * Private key for AML officer
- */
-export type SigningKey = Uint8Array & { [opaque_OfficerSigningKey]: true };
export interface OfficerAccount {
id: OfficerId;
- signingKey: SigningKey;
+ signingKey: EddsaPrivP;
}
export interface ReserveAccount {
id: ReservePub;
- signingKey: SigningKey;
+ signingKey: EddsaPrivP;
}
export type PaginationParams = {
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -86,8 +86,6 @@ import {
WireFee,
WithdrawalPlanchet,
} from "@gnu-taler/taler-util";
-// FIXME: Crypto should not use DB Types!
-import { DenominationRecord, timestampProtocolFromDb } from "../db.js";
import {
CreateRecoupRefreshReqRequest,
CreateRecoupReqRequest,
@@ -588,8 +586,18 @@ export interface GlobalFeesValidationRequest {
}
export interface DenominationValidationRequest {
- denom: DenominationRecord;
+ stampStart: TalerProtocolTimestamp;
+ stampExpireWithdraw: TalerProtocolTimestamp;
+ stampExpireDeposit: TalerProtocolTimestamp;
+ stampExpireLegal: TalerProtocolTimestamp;
+ value: AmountJson;
+ feeWithdraw: AmountJson;
+ feeDeposit: AmountJson;
+ feeRefresh: AmountJson;
+ feeRefund: AmountJson;
+ denomPubHash: string;
masterPub: string;
+ masterSig: string;
}
export interface PaymentSignatureValidationRequest {
@@ -1023,35 +1031,22 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
tci: TalerCryptoInterfaceR,
req: DenominationValidationRequest,
): Promise<ValidationResult> {
- const { masterPub, denom } = req;
- const value: AmountJson = Amounts.parseOrThrow(denom.value);
+ const value: AmountJson = Amounts.parseOrThrow(req.value);
const p = buildSigPS(TalerSignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
- .put(decodeCrock(masterPub))
- .put(timestampRoundedToBuffer(timestampProtocolFromDb(denom.stampStart)))
- .put(
- timestampRoundedToBuffer(
- timestampProtocolFromDb(denom.stampExpireWithdraw),
- ),
- )
- .put(
- timestampRoundedToBuffer(
- timestampProtocolFromDb(denom.stampExpireDeposit),
- ),
- )
- .put(
- timestampRoundedToBuffer(
- timestampProtocolFromDb(denom.stampExpireLegal),
- ),
- )
+ .put(decodeCrock(req.masterPub))
+ .put(timestampRoundedToBuffer(req.stampStart))
+ .put(timestampRoundedToBuffer(req.stampExpireWithdraw))
+ .put(timestampRoundedToBuffer(req.stampExpireDeposit))
+ .put(timestampRoundedToBuffer(req.stampExpireLegal))
.put(amountToBuffer(value))
- .put(amountToBuffer(denom.fees.feeWithdraw))
- .put(amountToBuffer(denom.fees.feeDeposit))
- .put(amountToBuffer(denom.fees.feeRefresh))
- .put(amountToBuffer(denom.fees.feeRefund))
- .put(decodeCrock(denom.denomPubHash))
+ .put(amountToBuffer(req.feeWithdraw))
+ .put(amountToBuffer(req.feeDeposit))
+ .put(amountToBuffer(req.feeRefresh))
+ .put(amountToBuffer(req.feeRefund))
+ .put(decodeCrock(req.denomPubHash))
.build();
- const sig = decodeCrock(denom.masterSig);
- const pub = decodeCrock(masterPub);
+ const sig = decodeCrock(req.masterSig);
+ const pub = decodeCrock(req.masterSig);
const res = eddsaVerify(p, sig, pub);
return { valid: res };
},
diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts
@@ -150,6 +150,7 @@ import {
timestampAbsoluteFromDb,
timestampPreciseFromDb,
timestampPreciseToDb,
+ timestampProtocolFromDb,
} from "./db.js";
import {
selectForcedWithdrawalDenominations,
@@ -1805,6 +1806,28 @@ async function processPlanchetVerifyAndStoreCoin(
);
}
+async function isValidDenomRecord(
+ wex: WalletExecutionContext,
+ exchangeMasterPub: string,
+ d: DenominationRecord,
+): Promise<boolean> {
+ const res = await wex.cryptoApi.isValidDenom({
+ masterPub: exchangeMasterPub,
+ denomPubHash: d.denomPubHash,
+ feeDeposit: Amounts.parseOrThrow(d.fees.feeDeposit),
+ feeRefresh: Amounts.parseOrThrow(d.fees.feeRefresh),
+ feeRefund: Amounts.parseOrThrow(d.fees.feeRefund),
+ feeWithdraw: Amounts.parseOrThrow(d.fees.feeWithdraw),
+ masterSig: d.masterSig,
+ stampExpireDeposit: timestampProtocolFromDb(d.stampExpireDeposit),
+ stampExpireLegal: timestampProtocolFromDb(d.stampExpireLegal),
+ stampExpireWithdraw: timestampProtocolFromDb(d.stampExpireWithdraw),
+ stampStart: timestampProtocolFromDb(d.stampExpireWithdraw),
+ value: Amounts.parseOrThrow(d.value),
+ });
+ return res.valid;
+}
+
/**
* Make sure that denominations that currently can be used for withdrawal
* are validated, and the result of validation is stored in the database.
@@ -1859,11 +1882,11 @@ export async function updateWithdrawalDenoms(
if (wex.ws.config.testing.insecureTrustExchange) {
valid = true;
} else {
- const res = await wex.cryptoApi.isValidDenom({
+ valid = await isValidDenomRecord(
+ wex,
+ exchangeDetails.masterPublicKey,
denom,
- masterPub: exchangeDetails.masterPublicKey,
- });
- valid = res.valid;
+ );
}
logger.trace(`Done validating ${denom.denomPubHash}`);
if (!valid) {