commit 8e3eb730b5f4c6b2ae9b99e5b2144a899e2a93a0
parent ecacdafcf6746189d8395786b684e662f053de07
Author: Iván Ávalos <avalos@disroot.org>
Date: Sun, 6 Jul 2025 17:53:20 +0200
wallet-core: add TokenAvailabilityHint to getChoicesForPayment
Diffstat:
3 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/packages/taler-harness/src/integrationtests/test-wallet-tokens.ts b/packages/taler-harness/src/integrationtests/test-wallet-tokens.ts
@@ -34,6 +34,7 @@ import {
succeedOrThrow,
TalerMerchantInstanceHttpClient,
TalerProtocolTimestamp,
+ TokenAvailabilityHint,
TokenFamilyKind,
} from "@gnu-taler/taler-util";
import { logger } from "./test-tops-challenger-twice.js";
@@ -258,6 +259,7 @@ export async function runWalletTokensTest(t: GlobalTestState) {
for (const tf in tokenDetails?.perTokenFamily ?? t.fail()) {
t.assertTrue(tokenDetails?.perTokenFamily[tf].available === 1);
t.assertTrue(tokenDetails?.perTokenFamily[tf].requested === 1);
+ t.assertTrue(tokenDetails?.perTokenFamily[tf].causeHint === undefined);
break;
}
}
@@ -321,6 +323,8 @@ export async function runWalletTokensTest(t: GlobalTestState) {
for (const tf in tokenDetails?.perTokenFamily ?? t.fail()) {
t.assertTrue(tokenDetails?.perTokenFamily[tf].available === 0);
t.assertTrue(tokenDetails?.perTokenFamily[tf].requested === 1);
+ t.assertTrue(tokenDetails?.perTokenFamily[tf].causeHint ===
+ TokenAvailabilityHint.WalletTokensAvailableInsufficient);
break;
}
}
@@ -431,6 +435,7 @@ export async function runWalletTokensTest(t: GlobalTestState) {
for (const tf in tokenDetails?.perTokenFamily ?? t.fail()) {
t.assertTrue(tokenDetails?.perTokenFamily[tf].available === 1);
t.assertTrue(tokenDetails?.perTokenFamily[tf].requested === 1);
+ t.assertTrue(tokenDetails?.perTokenFamily[tf].causeHint === undefined);
break;
}
}
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -914,6 +914,7 @@ export interface PaymentTokenAvailabilityDetails {
perTokenFamily: {
[slug: string]: {
+ causeHint?: TokenAvailabilityHint;
requested: number;
available: number;
unexpected: number;
@@ -922,6 +923,12 @@ export interface PaymentTokenAvailabilityDetails {
};
}
+export enum TokenAvailabilityHint {
+ WalletTokensAvailableInsufficient = "wallet-tokens-available-insufficient",
+ MerchantUnexpected = "merchant-unexpected",
+ MerchantUntrusted = "merchant-untrusted",
+}
+
export const codecForPayMerchantInsufficientBalanceDetails =
(): Codec<PaymentInsufficientBalanceDetails> =>
buildCodecForObject<PaymentInsufficientBalanceDetails>()
diff --git a/packages/taler-wallet-core/src/tokenSelection.ts b/packages/taler-wallet-core/src/tokenSelection.ts
@@ -25,6 +25,7 @@ import {
MerchantContractTokenDetails,
MerchantContractTokenKind,
PaymentTokenAvailabilityDetails,
+ TokenAvailabilityHint,
} from "@gnu-taler/taler-util";
import {
timestampProtocolFromDb,
@@ -300,11 +301,26 @@ export function selectTokenCandidates(
details.tokensUnexpected += details.perTokenFamily[slug].unexpected;
details.tokensUntrusted += details.perTokenFamily[slug].untrusted;
- if (usable.length < requested) {
+ // calculate token availability hint
+ const perTokenFamily = details.perTokenFamily[slug];
+ let hint: TokenAvailabilityHint | undefined;
+ if (perTokenFamily.available < perTokenFamily.requested) {
+ if (perTokenFamily.untrusted > 0) {
+ hint = TokenAvailabilityHint.MerchantUntrusted;
+ } else {
+ hint = TokenAvailabilityHint.WalletTokensAvailableInsufficient;
+ }
+
insufficient = true;
+ details.perTokenFamily[slug].causeHint = hint;
continue;
+ } else {
+ if (perTokenFamily.unexpected > 0) {
+ hint = TokenAvailabilityHint.MerchantUnexpected;
+ }
}
+ details.perTokenFamily[slug].causeHint = hint;
tokens.push(...usable.slice(0, requested));
}