/*
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 {
AbsoluteTime,
MerchantContractTerms,
Duration,
} from "@gnu-taler/taler-util";
import {
WalletApiOperation,
HarnessExchangeBankAccount,
} from "@gnu-taler/taler-wallet-core";
import { CoinConfig, defaultCoinConfig } from "../harness/denomStructures.js";
import {
DbInfo,
ExchangeService,
GlobalTestState,
MerchantService,
setupDb,
WalletCli,
WalletClient,
} from "../harness/harness.js";
import {
LibeufinNexusApi,
LibeufinNexusService,
LibeufinSandboxApi,
LibeufinSandboxService,
} from "../harness/libeufin.js";
import {
createWalletDaemonWithClient,
makeTestPaymentV2,
} from "../harness/helpers.js";
const exchangeIban = "DE71500105179674997361";
const customerIban = "DE84500105176881385584";
const customerBic = "BELADEBEXXX";
const merchantIban = "DE42500105171245624648";
export interface LibeufinTestEnvironment {
commonDb: DbInfo;
exchange: ExchangeService;
exchangeBankAccount: HarnessExchangeBankAccount;
merchant: MerchantService;
walletClient: WalletClient;
libeufinSandbox: LibeufinSandboxService;
libeufinNexus: LibeufinNexusService;
}
/**
* Create a Taler environment with LibEuFin and an EBICS account.
*/
export async function createLibeufinTestEnvironment(
t: GlobalTestState,
coinConfig: CoinConfig[] = defaultCoinConfig.map((x) => x("EUR")),
): Promise {
const db = await setupDb(t);
const libeufinSandbox = await LibeufinSandboxService.create(t, {
httpPort: 5010,
databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-sandbox.sqlite3`,
});
await libeufinSandbox.start();
await libeufinSandbox.pingUntilAvailable();
const libeufinNexus = await LibeufinNexusService.create(t, {
httpPort: 5011,
databaseJdbcUri: `jdbc:sqlite:${t.testDir}/libeufin-nexus.sqlite3`,
});
await libeufinNexus.start();
await libeufinNexus.pingUntilAvailable();
await LibeufinSandboxApi.createEbicsHost(libeufinSandbox, "host01");
// Subscriber and bank Account for the exchange
await LibeufinSandboxApi.createDemobankAccount(
"exchangeacct",
"password-unused",
{ baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/access-api/" },
exchangeIban,
);
await LibeufinSandboxApi.createDemobankEbicsSubscriber(
{
hostID: "host01",
partnerID: "partner01",
userID: "user01",
},
"exchangeacct",
{ baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/" },
);
await LibeufinSandboxApi.createDemobankAccount(
"merchantacct",
"password-unused",
{ baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/access-api/" },
merchantIban,
);
await LibeufinSandboxApi.createDemobankEbicsSubscriber(
{
hostID: "host01",
partnerID: "partner02",
userID: "user02",
},
"merchantacct",
{ baseUrl: libeufinSandbox.baseUrl + "/demobanks/default/" },
);
await LibeufinNexusApi.createEbicsBankConnection(libeufinNexus, {
name: "myconn",
ebicsURL: "http://localhost:5010/ebicsweb",
hostID: "host01",
partnerID: "partner01",
userID: "user01",
});
await LibeufinNexusApi.connectBankConnection(libeufinNexus, "myconn");
await LibeufinNexusApi.fetchAccounts(libeufinNexus, "myconn");
await LibeufinNexusApi.importConnectionAccount(
libeufinNexus,
"myconn",
"exchangeacct",
"myacct",
);
await LibeufinNexusApi.createTwgFacade(libeufinNexus, {
name: "twg1",
accountName: "myacct",
connectionName: "myconn",
currency: "EUR",
reserveTransferLevel: "report",
});
await LibeufinNexusApi.createUser(libeufinNexus, {
username: "twguser",
password: "twgpw",
});
await LibeufinNexusApi.postPermission(libeufinNexus, {
action: "grant",
permission: {
subjectType: "user",
subjectId: "twguser",
resourceType: "facade",
resourceId: "twg1",
permissionName: "facade.talerWireGateway.history",
},
});
await LibeufinNexusApi.postPermission(libeufinNexus, {
action: "grant",
permission: {
subjectType: "user",
subjectId: "twguser",
resourceType: "facade",
resourceId: "twg1",
permissionName: "facade.talerWireGateway.transfer",
},
});
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "EUR",
httpPort: 8081,
database: db.connStr,
});
const merchant = await MerchantService.create(t, {
name: "testmerchant-1",
currency: "EUR",
httpPort: 8083,
database: db.connStr,
});
const exchangeBankAccount: HarnessExchangeBankAccount = {
accountName: "twguser",
accountPassword: "twgpw",
accountPaytoUri: `payto://iban/${exchangeIban}?receiver-name=Exchange`,
wireGatewayApiBaseUrl:
"http://localhost:5011/facades/twg1/taler-wire-gateway/",
};
exchange.addBankAccount("1", exchangeBankAccount);
exchange.addCoinConfigList(coinConfig);
await exchange.start();
await exchange.pingUntilAvailable();
merchant.addExchange(exchange);
await merchant.start();
await merchant.pingUntilAvailable();
await merchant.addInstanceWithWireAccount({
id: "default",
name: "Default Instance",
paytoUris: [`payto://iban/${merchantIban}?receiver-name=Merchant`],
defaultWireTransferDelay: Duration.toTalerProtocolDuration(
Duration.getZero(),
),
});
console.log("setup done!");
const { walletClient } = await createWalletDaemonWithClient(t, {
name: "default ",
});
return {
commonDb: db,
exchange,
merchant,
walletClient,
exchangeBankAccount,
libeufinNexus,
libeufinSandbox,
};
}
/**
* Run basic test with LibEuFin.
*/
export async function runLibeufinBasicTest(t: GlobalTestState) {
// Set up test environment
const { walletClient, exchange, merchant, libeufinSandbox, libeufinNexus } =
await createLibeufinTestEnvironment(t);
await walletClient.call(WalletApiOperation.AddExchange, {
exchangeBaseUrl: exchange.baseUrl,
});
const wr = await walletClient.call(
WalletApiOperation.AcceptManualWithdrawal,
{
exchangeBaseUrl: exchange.baseUrl,
amount: "EUR:15",
},
);
const reservePub: string = wr.reservePub;
await LibeufinSandboxApi.simulateIncomingTransaction(
libeufinSandbox,
"exchangeacct",
{
amount: "EUR:15.00",
debtorBic: customerBic,
debtorIban: customerIban,
debtorName: "Jane Customer",
subject: `Taler Top-up ${reservePub}`,
},
);
await LibeufinNexusApi.fetchTransactions(libeufinNexus, "myacct");
await exchange.runWirewatchOnce();
await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});
const bal = await walletClient.call(WalletApiOperation.GetBalances, {});
console.log("balances", JSON.stringify(bal, undefined, 2));
t.assertAmountEquals(bal.balances[0].available, "EUR:14.7");
const order: Partial = {
summary: "Buy me!",
amount: "EUR:5",
fulfillment_url: "taler://fulfillment-success/thx",
wire_transfer_deadline: AbsoluteTime.toProtocolTimestamp(
AbsoluteTime.now(),
),
};
await makeTestPaymentV2(t, { walletClient, merchant, order });
await exchange.runAggregatorOnce();
await exchange.runTransferOnce();
await LibeufinNexusApi.submitAllPaymentInitiations(libeufinNexus, "myacct");
const exchangeTransactions = await LibeufinSandboxApi.getAccountTransactions(
libeufinSandbox,
"exchangeacct",
);
console.log(
"exchange transactions:",
JSON.stringify(exchangeTransactions, undefined, 2),
);
t.assertDeepEqual(
exchangeTransactions.payments[0].creditDebitIndicator,
"credit",
);
t.assertDeepEqual(
exchangeTransactions.payments[1].creditDebitIndicator,
"debit",
);
t.assertDeepEqual(exchangeTransactions.payments[1].debtorIban, exchangeIban);
t.assertDeepEqual(
exchangeTransactions.payments[1].creditorIban,
merchantIban,
);
}
runLibeufinBasicTest.suites = ["libeufin"];