taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

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:
Mpackages/taler-harness/src/integrationtests/test-wallet-tokens.ts | 5+++++
Mpackages/taler-util/src/types-taler-wallet.ts | 7+++++++
Mpackages/taler-wallet-core/src/tokenSelection.ts | 18+++++++++++++++++-
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)); }