/* 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 */ /** * Imports. */ import { GlobalTestState } from "../harness/harness.js"; import { createSimpleTestkudosEnvironmentV2 } from "../harness/helpers.js"; import { BankAccessApiClient, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { j2s, NotificationType, TransactionMajorState, TransactionMinorState, TransactionType, WithdrawalType, } from "@gnu-taler/taler-util"; /** * Run test for basic, bank-integrated withdrawal. */ export async function runWithdrawalBankIntegratedTest(t: GlobalTestState) { // Set up test environment const { walletClient, bank, exchange } = await createSimpleTestkudosEnvironmentV2(t); // Create a withdrawal operation const bankAccessApiClient = new BankAccessApiClient({ allowHttp: true, baseUrl: bank.bankAccessApiBaseUrl, }); const user = await bankAccessApiClient.createRandomBankUser(); bankAccessApiClient.setAuth(user); const wop = await bankAccessApiClient.createWithdrawalOperation( user.username, "TESTKUDOS:10", ); // Hand it to the wallet const r1 = await walletClient.client.call( WalletApiOperation.GetWithdrawalDetailsForUri, { talerWithdrawUri: wop.taler_withdraw_uri, }, ); // Withdraw const r2 = await walletClient.client.call( WalletApiOperation.AcceptBankIntegratedWithdrawal, { exchangeBaseUrl: exchange.baseUrl, talerWithdrawUri: wop.taler_withdraw_uri, }, ); const withdrawalBankConfirmedCond = walletClient.waitForNotificationCond( (x) => { return ( x.type === NotificationType.TransactionStateTransition && x.transactionId === r2.transactionId && x.newTxState.major === TransactionMajorState.Pending && x.newTxState.minor === TransactionMinorState.ExchangeWaitReserve ); }, ); const withdrawalFinishedCond = walletClient.waitForNotificationCond((x) => { return ( x.type === NotificationType.TransactionStateTransition && x.transactionId === r2.transactionId && x.newTxState.major === TransactionMajorState.Done ); }); const withdrawalReserveReadyCond = walletClient.waitForNotificationCond( (x) => { return ( x.type === NotificationType.TransactionStateTransition && x.transactionId === r2.transactionId && x.newTxState.major === TransactionMajorState.Pending && x.newTxState.minor === TransactionMinorState.WithdrawCoins ); }, ); // Do it twice to check idempotency const r3 = await walletClient.client.call( WalletApiOperation.AcceptBankIntegratedWithdrawal, { exchangeBaseUrl: exchange.baseUrl, talerWithdrawUri: wop.taler_withdraw_uri, }, ); await exchange.stopWirewatch(); // Check status before withdrawal is confirmed by bank. { const txn = await walletClient.client.call( WalletApiOperation.GetTransactions, {}, ); console.log("transactions before confirmation:", j2s(txn)); const tx0 = txn.transactions[0]; t.assertTrue(tx0.type === TransactionType.Withdrawal); t.assertTrue( tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi, ); t.assertTrue(tx0.withdrawalDetails.confirmed === false); t.assertTrue(tx0.withdrawalDetails.reserveIsReady === false); } // Confirm it await bankAccessApiClient.confirmWithdrawalOperation(user.username, wop); await withdrawalBankConfirmedCond; // Check status after withdrawal is confirmed by bank, // but before funds are wired to the exchange. { const txn = await walletClient.client.call( WalletApiOperation.GetTransactions, {}, ); console.log("transactions after confirmation:", j2s(txn)); const tx0 = txn.transactions[0]; t.assertTrue(tx0.type === TransactionType.Withdrawal); t.assertTrue( tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi, ); t.assertTrue(tx0.withdrawalDetails.confirmed === true); t.assertTrue(tx0.withdrawalDetails.reserveIsReady === false); } await exchange.startWirewatch(); await withdrawalReserveReadyCond; // Check status after funds were wired. { const txn = await walletClient.client.call( WalletApiOperation.GetTransactions, {}, ); console.log("transactions after reserve ready:", j2s(txn)); const tx0 = txn.transactions[0]; t.assertTrue(tx0.type === TransactionType.Withdrawal); t.assertTrue( tx0.withdrawalDetails.type === WithdrawalType.TalerBankIntegrationApi, ); t.assertTrue(tx0.withdrawalDetails.confirmed === true); t.assertTrue(tx0.withdrawalDetails.reserveIsReady === true); } await withdrawalFinishedCond; // Check balance const balResp = await walletClient.client.call( WalletApiOperation.GetBalances, {}, ); t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available); const txn = await walletClient.client.call( WalletApiOperation.GetTransactions, {}, ); console.log(`transactions: ${j2s(txn)}`); } runWithdrawalBankIntegratedTest.suites = ["wallet"];