taler-typescript-core

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

commit 5108473b16b7fb660689c7d00f74a5493198a131
parent 2bdf20e63fdf67bf978ab46f528f1a7ff9dcc89b
Author: Florian Dold <florian@dold.me>
Date:   Wed, 14 May 2025 19:46:16 +0200

wallet-core: fix transition when kyc-wallet returns 200, test scenario

Diffstat:
Apackages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal-change-manual.ts | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-harness/src/integrationtests/testrunner.ts | 2++
Mpackages/taler-wallet-core/src/exchanges.ts | 8++++++--
Mpackages/taler-wallet-core/src/withdraw.ts | 21+++++++++++++++------
4 files changed, 129 insertions(+), 8 deletions(-)

diff --git a/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal-change-manual.ts b/packages/taler-harness/src/integrationtests/test-kyc-balance-withdrawal-change-manual.ts @@ -0,0 +1,106 @@ +/* + This file is part of GNU Taler + (C) 2020 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * Imports. + */ +import { + Configuration, + TalerWireGatewayHttpClient, + TransactionIdStr, + TransactionMajorState, +} from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { + configureCommonKyc, + createKycTestkudosEnvironment, +} from "../harness/environments.js"; +import { GlobalTestState } from "../harness/harness.js"; + +function adjustExchangeConfig(config: Configuration): void { + configureCommonKyc(config); + + config.setString("KYC-RULE-R1", "operation_type", "balance"); + config.setString("KYC-RULE-R1", "enabled", "yes"); + config.setString("KYC-RULE-R1", "exposed", "yes"); + config.setString("KYC-RULE-R1", "is_and_combinator", "yes"); + config.setString("KYC-RULE-R1", "threshold", "TESTKUDOS:10"); + config.setString("KYC-RULE-R1", "timeframe", "forever"); + config.setString("KYC-RULE-R1", "next_measures", "M1"); + + config.setString("KYC-MEASURE-M1", "check_name", "C1"); + config.setString("KYC-MEASURE-M1", "context", "{}"); + config.setString("KYC-MEASURE-M1", "program", "NONE"); + + config.setString("KYC-CHECK-C1", "type", "INFO"); + config.setString("KYC-CHECK-C1", "description", "my check!"); + config.setString("KYC-CHECK-C1", "fallback", "FREEZE"); +} + +export async function runKycBalanceWithdrawalChangeManualTest( + t: GlobalTestState, +) { + // Set up test environment + + const { walletClient, bankClient, exchange, exchangeBankAccount } = + await createKycTestkudosEnvironment(t, { + adjustExchangeConfig, + }); + + const mwResp = await walletClient.call( + WalletApiOperation.AcceptManualWithdrawal, + { + // Specify larger amount than what will be in the reserve. + amount: "TESTKUDOS:20", + exchangeBaseUrl: exchange.baseUrl, + }, + ); + + await exchange.stop(); + + await exchange.modifyConfig(async (config) => { + config.setString("KYC-RULE-R1", "enabled", "NO"); + }); + + await exchange.start(); + + const user = await bankClient.createRandomBankUser(); + + // Next, do a manual withdrawal. + const wireGatewayApiClient = new TalerWireGatewayHttpClient( + exchangeBankAccount.wireGatewayApiBaseUrl, + ); + + const reservePub = mwResp.reservePub; + + await wireGatewayApiClient.addIncoming({ + auth: exchangeBankAccount.wireGatewayAuth, + body: { + amount: "TESTKUDOS:20", + debit_account: user.accountPaytoUri, + reserve_pub: reservePub, + }, + }); + + await walletClient.call(WalletApiOperation.TestingWaitTransactionState, { + transactionId: mwResp.transactionId as TransactionIdStr, + txState: { + major: TransactionMajorState.Done, + }, + }); +} + +runKycBalanceWithdrawalChangeManualTest.suites = ["wallet"]; diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts @@ -59,6 +59,7 @@ import { runForcedSelectionTest } from "./test-forced-selection.js"; import { runKnownAccountsTest } from "./test-known-accounts.js"; import { runKycAmpFailureTest } from "./test-kyc-amp-failure.js"; import { runKycAmpTimeoutTest } from "./test-kyc-amp-timeout.js"; +import { runKycBalanceWithdrawalChangeManualTest } from "./test-kyc-balance-withdrawal-change-manual.js"; import { runKycBalanceWithdrawalTest } from "./test-kyc-balance-withdrawal.js"; import { runKycChallengerTest } from "./test-kyc-challenger.js"; import { runKycDecisionAttrTest } from "./test-kyc-decision-attr.js"; @@ -339,6 +340,7 @@ const allTests: TestMainFunction[] = [ runTopsAmlLegiTest, runTopsChallengerTwiceTest, runKycFormBadMeasureTest, + runKycBalanceWithdrawalChangeManualTest, ]; export interface TestRunSpec { diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts @@ -3565,7 +3565,6 @@ async function handleExchangeKycPendingWallet( switch (res.status) { case HttpStatusCode.Ok: { // KYC somehow already passed - // FIXME: Store next threshold and timestamp! const walletKycResp = await readSuccessResponseJsonOrThrow( res, codecForAmlWalletKycCheckResponse(), @@ -3810,11 +3809,16 @@ async function handleExchangeKycPendingLegitimization( resp, codecForAccountKycStatus(), ); - logger.trace(`balance KYC account status: ${j2s(accountKycStatus)}`); + logger.info(`balance KYC account status: ${j2s(accountKycStatus)}`); const nextLimit = findNextBalanceLimit( accountKycStatus, reserve.thresholdGranted, ); + logger.info( + `setting next limit to: ${ + nextLimit ? Amounts.stringify(nextLimit) : "undefined" + }`, + ); return handleExchangeKycSuccess(wex, exchange.baseUrl, nextLimit); } case HttpStatusCode.Accepted: diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts @@ -1067,17 +1067,26 @@ async function processWithdrawalGroupBalanceKyc( }); if (ret.result === "ok") { - await ctx.transition({}, async (wg) => { + const transitionInfo = await ctx.transition({}, async (wg) => { if (!wg) { return TransitionResult.stay(); } - if (wg.status !== WithdrawalGroupStatus.PendingBalanceKyc) { - return TransitionResult.stay(); + switch (wg.status) { + case WithdrawalGroupStatus.PendingBalanceKyc: + case WithdrawalGroupStatus.PendingBalanceKycInit: { + wg.status = WithdrawalGroupStatus.PendingReady; + return TransitionResult.transition(wg); + } + default: { + return TransitionResult.stay(); + } } - wg.status = WithdrawalGroupStatus.PendingReady; - return TransitionResult.transition(wg); }); - return TaskRunResult.progress(); + if (transitionInfo) { + return TaskRunResult.progress(); + } else { + return TaskRunResult.backoff(); + } } else if ( withdrawalGroup.status === WithdrawalGroupStatus.PendingBalanceKycInit && ret.walletKycStatus === ExchangeWalletKycStatus.Legi