diff options
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.ts | 238 |
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"]; |