aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts')
-rw-r--r--packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts238
1 files changed, 238 insertions, 0 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts b/packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts
new file mode 100644
index 000000000..cf1c8206e
--- /dev/null
+++ b/packages/taler-harness/src/integrationtests/test-kyc-withdrawal-verboten.ts
@@ -0,0 +1,238 @@
+/*
+ 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 {
+ Duration,
+ NotificationType,
+ TalerProtocolTimestamp,
+ TransactionMajorState,
+ TransactionMinorState,
+ TransactionType,
+} from "@gnu-taler/taler-util";
+import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import {
+ createKycTestkudosEnvironment,
+ postAmlDecision,
+ postAmlDecisionNoRules,
+} from "../harness/environments.js";
+import { GlobalTestState } from "../harness/harness.js";
+
+export async function runKycWithdrawalVerbotenTest(t: GlobalTestState) {
+ // Set up test environment
+
+ const { walletClient, bankClient, exchange, amlKeypair } =
+ await createKycTestkudosEnvironment(t, {
+ adjustExchangeConfig(config) {
+ config.setString("exchange", "enable_kyc", "yes");
+
+ config.setString("KYC-RULE-R1", "operation_type", "withdraw");
+ 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:5");
+ config.setString("KYC-RULE-R1", "timeframe", "1d");
+ config.setString("KYC-RULE-R1", "next_measures", "M1");
+
+ config.setString("KYC-RULE-R2", "operation_type", "withdraw");
+ config.setString("KYC-RULE-R2", "enabled", "yes");
+ config.setString("KYC-RULE-R2", "exposed", "yes");
+ config.setString("KYC-RULE-R2", "is_and_combinator", "yes");
+ config.setString("KYC-RULE-R2", "threshold", "TESTKUDOS:300");
+ config.setString("KYC-RULE-R2", "timeframe", "1d");
+ config.setString("KYC-RULE-R2", "next_measures", "verboten");
+
+ config.setString("KYC-MEASURE-M1", "check_name", "C1");
+ config.setString("KYC-MEASURE-M1", "context", "{}");
+ config.setString("KYC-MEASURE-M1", "program", "P1");
+
+ config.setString("AML-PROGRAM-P1", "command", "/bin/true");
+ config.setString("AML-PROGRAM-P1", "enabled", "true");
+ config.setString("AML-PROGRAM-P1", "description", "this does nothing");
+ config.setString("AML-PROGRAM-P1", "fallback", "M1");
+
+ config.setString("KYC-CHECK-C1", "type", "INFO");
+ config.setString("KYC-CHECK-C1", "description", "my check!");
+ config.setString("KYC-CHECK-C1", "fallback", "M1");
+ },
+ });
+
+ // Withdraw digital cash into the wallet.
+
+ const amount = "TESTKUDOS:20";
+ const user = await bankClient.createRandomBankUser();
+ bankClient.setAuth({
+ username: user.username,
+ password: user.password,
+ });
+
+ const wop = await bankClient.createWithdrawalOperation(user.username, amount);
+
+ // Hand it to the wallet
+
+ const withdrawalUrlInfo = await walletClient.client.call(
+ WalletApiOperation.GetWithdrawalDetailsForUri,
+ {
+ talerWithdrawUri: wop.taler_withdraw_uri,
+ },
+ );
+
+ const withdrawalAmountInfo = await walletClient.call(
+ WalletApiOperation.GetWithdrawalDetailsForAmount,
+ {
+ amount: withdrawalUrlInfo.amount!,
+ exchangeBaseUrl: withdrawalUrlInfo.possibleExchanges[0].exchangeBaseUrl,
+ },
+ );
+
+ t.assertTrue(!!withdrawalAmountInfo.kycHardLimit);
+ t.assertAmountEquals(withdrawalAmountInfo.kycHardLimit, "TESTKUDOS:300");
+
+ // Withdraw
+
+ const acceptResp = await walletClient.client.call(
+ WalletApiOperation.AcceptBankIntegratedWithdrawal,
+ {
+ exchangeBaseUrl: exchange.baseUrl,
+ talerWithdrawUri: wop.taler_withdraw_uri,
+ },
+ );
+
+ const withdrawalTxId = acceptResp.transactionId;
+
+ // Confirm it
+
+ await bankClient.confirmWithdrawalOperation(user.username, {
+ withdrawalOperationId: wop.withdrawal_id,
+ });
+
+ t.logStep("waiting for pending(kyc-required)");
+
+ const kycNotificationCond = walletClient.waitForNotificationCond((x) => {
+ if (
+ x.type === NotificationType.TransactionStateTransition &&
+ x.transactionId === withdrawalTxId &&
+ x.newTxState.major === TransactionMajorState.Pending &&
+ x.newTxState.minor === TransactionMinorState.KycRequired
+ ) {
+ return x;
+ }
+ return false;
+ });
+
+ await kycNotificationCond;
+
+ const txDet = await walletClient.call(WalletApiOperation.GetTransactionById, {
+ transactionId: withdrawalTxId,
+ });
+
+ t.assertDeepEqual(txDet.type, TransactionType.Withdrawal);
+
+ const kycPaytoHash = txDet.kycPaytoHash;
+ t.assertTrue(!!kycPaytoHash);
+
+ t.logStep("posting aml decision");
+
+ await postAmlDecisionNoRules(t, {
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ exchangeBaseUrl: exchange.baseUrl,
+ paytoHash: kycPaytoHash,
+ });
+
+ t.logStep("waiting for withdrawal to be done");
+
+ const doneNotificationCond = walletClient.waitForNotificationCond((x) => {
+ if (
+ x.type === NotificationType.TransactionStateTransition &&
+ x.transactionId === withdrawalTxId &&
+ x.newTxState.major === TransactionMajorState.Done
+ ) {
+ return x;
+ }
+ return false;
+ });
+
+ await doneNotificationCond;
+
+ // Now that the first withdrawal has succeeded, we freeze the account.
+
+ await postAmlDecision(t, {
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ exchangeBaseUrl: exchange.baseUrl,
+ paytoHash: kycPaytoHash,
+ newRules: {
+ custom_measures: {},
+ expiration_time: TalerProtocolTimestamp.never(),
+ rules: [
+ {
+ operation_type: "WITHDRAW",
+ display_priority: 1,
+ measures: ["verboten"],
+ threshold: "TESTKUDOS:0",
+ timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
+ exposed: true,
+ is_and_combinator: false,
+ },
+ ],
+ },
+ });
+
+ const wop2 = await bankClient.createWithdrawalOperation(
+ user.username,
+ "TESTKUDOS:10",
+ );
+
+ const acceptResp2 = await walletClient.client.call(
+ WalletApiOperation.AcceptBankIntegratedWithdrawal,
+ {
+ exchangeBaseUrl: exchange.baseUrl,
+ talerWithdrawUri: wop2.taler_withdraw_uri,
+ },
+ );
+
+ const withdrawalTxId2 = acceptResp2.transactionId;
+
+ // Confirm it
+
+ await bankClient.confirmWithdrawalOperation(user.username, {
+ withdrawalOperationId: wop2.withdrawal_id,
+ });
+
+ await t.runSpanAsync(
+ "waiting for second withdrawal to require KYC",
+ async () => {
+ const kycNotificationCond2 = walletClient.waitForNotificationCond((x) => {
+ if (
+ x.type === NotificationType.TransactionStateTransition &&
+ x.transactionId === withdrawalTxId2 &&
+ x.newTxState.major === TransactionMajorState.Pending &&
+ x.newTxState.minor === TransactionMinorState.KycRequired
+ ) {
+ return x;
+ }
+ return false;
+ });
+
+ await kycNotificationCond2;
+ },
+ );
+}
+
+runKycWithdrawalVerbotenTest.suites = ["wallet"];