[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] branch master updated: implement fakebank withdrawal
From: |
gnunet |
Subject: |
[taler-wallet-core] branch master updated: implement fakebank withdrawal |
Date: |
Thu, 14 Oct 2021 11:36:48 +0200 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository wallet-core.
The following commit(s) were added to refs/heads/master by this push:
new c5326486 implement fakebank withdrawal
c5326486 is described below
commit c53264869451ccbfbaf1976e01df8c7636163068
Author: Florian Dold <florian@dold.me>
AuthorDate: Thu Oct 14 11:36:43 2021 +0200
implement fakebank withdrawal
---
packages/taler-util/src/walletTypes.ts | 28 +++++++--
packages/taler-wallet-cli/src/index.ts | 24 ++++++-
.../src/integrationtests/harness.ts | 61 ++++++++++++++++++
.../src/integrationtests/helpers.ts | 33 +++++++---
...rawal-manual.ts => test-withdrawal-fakebank.ts} | 70 +++++++++++++--------
.../src/integrationtests/test-withdrawal-manual.ts | 4 --
.../src/integrationtests/testrunner.ts | 4 +-
packages/taler-wallet-core/src/wallet-api-types.ts | 13 +++-
packages/taler-wallet-core/src/wallet.ts | 73 +++++++++++++++++++---
9 files changed, 253 insertions(+), 57 deletions(-)
diff --git a/packages/taler-util/src/walletTypes.ts
b/packages/taler-util/src/walletTypes.ts
index 63ece1e6..6e68ee08 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -590,11 +590,11 @@ export interface GetExchangeTosResult {
* if any.
*/
acceptedEtag: string | undefined;
-
+
/**
* Accepted content type
*/
- contentType: string;
+ contentType: string;
}
export interface TestPayArgs {
@@ -658,9 +658,9 @@ export interface GetExchangeTosRequest {
export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest>
=>
buildCodecForObject<GetExchangeTosRequest>()
- .property("exchangeBaseUrl", codecForString())
- .property("acceptedFormat", codecOptional(codecForList(codecForString())))
- .build("GetExchangeTosRequest");
+ .property("exchangeBaseUrl", codecForString())
+ .property("acceptedFormat", codecOptional(codecForList(codecForString())))
+ .build("GetExchangeTosRequest");
export interface AcceptManualWithdrawalRequest {
exchangeBaseUrl: string;
@@ -734,7 +734,10 @@ export const codecForGetExchangeWithdrawalInfo = ():
Codec<GetExchangeWithdrawal
buildCodecForObject<GetExchangeWithdrawalInfo>()
.property("exchangeBaseUrl", codecForString())
.property("amount", codecForAmountJson())
- .property("tosAcceptedFormat",
codecOptional(codecForList(codecForString())))
+ .property(
+ "tosAcceptedFormat",
+ codecOptional(codecForList(codecForString())),
+ )
.build("GetExchangeWithdrawalInfo");
export interface AbortProposalRequest {
@@ -1029,3 +1032,16 @@ export const codecForSetWalletDeviceIdRequest = ():
Codec<SetWalletDeviceIdReque
buildCodecForObject<SetWalletDeviceIdRequest>()
.property("walletDeviceId", codecForString())
.build("SetWalletDeviceIdRequest");
+
+export interface WithdrawFakebankRequest {
+ amount: AmountString;
+ exchange: string;
+ bank: string;
+}
+
+export const codecForWithdrawFakebankRequest = ():
Codec<WithdrawFakebankRequest> =>
+ buildCodecForObject<WithdrawFakebankRequest>()
+ .property("amount", codecForAmountString())
+ .property("bank", codecForString())
+ .property("exchange", codecForString())
+ .build("WithdrawFakebankRequest");
diff --git a/packages/taler-wallet-cli/src/index.ts
b/packages/taler-wallet-cli/src/index.ts
index 0985ba88..a5e129d9 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -634,6 +634,29 @@ const advancedCli = walletCli.subcommand("advancedArgs",
"advanced", {
"Subcommands for advanced operations (only use if you know what you're
doing!).",
});
+advancedCli
+ .subcommand("withdrawFakebank", "withdraw-fakebank", {
+ help: "Withdraw via a fakebank.",
+ })
+ .requiredOption("exchange", ["--exchange"], clk.STRING, {
+ help: "Base URL of the exchange to use",
+ })
+ .requiredOption("amount", ["--amount"], clk.STRING, {
+ help: "Amount to withdraw (before fees)."
+ })
+ .requiredOption("bank", ["--bank"], clk.STRING, {
+ help: "Base URL of the Taler fakebank service.",
+ })
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ await wallet.client.call(WalletApiOperation.WithdrawFakebank, {
+ amount: args.withdrawFakebank.amount,
+ bank: args.withdrawFakebank.bank,
+ exchange: args.withdrawFakebank.exchange,
+ });
+ });
+ });
+
advancedCli
.subcommand("manualWithdrawalDetails", "manual-withdrawal-details", {
help: "Query withdrawal fees.",
@@ -1064,6 +1087,5 @@ export function main() {
logger.warn("Allowing withdrawal of late denominations for debugging");
walletCoreDebugFlags.denomselAllowLate = true;
}
- logger.trace(`running wallet-cli with`, process.argv);
walletCli.run();
}
diff --git a/packages/taler-wallet-cli/src/integrationtests/harness.ts
b/packages/taler-wallet-cli/src/integrationtests/harness.ts
index a3a6e9e1..6644e567 100644
--- a/packages/taler-wallet-cli/src/integrationtests/harness.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/harness.ts
@@ -395,6 +395,11 @@ export interface BankConfig {
maxDebt?: string;
}
+export interface FakeBankConfig {
+ currency: string;
+ httpPort: number;
+}
+
function setTalerPaths(config: Configuration, home: string) {
config.setString("paths", "taler_home", home);
// We need to make sure that the path of taler_runtime_dir isn't too long,
@@ -714,6 +719,62 @@ export class BankService implements BankServiceInterface {
}
}
+export class FakeBankService {
+ proc: ProcessWrapper | undefined;
+
+ static fromExistingConfig(gc: GlobalTestState): FakeBankService {
+ const cfgFilename = gc.testDir + "/bank.conf";
+ console.log("reading fakebank config from", cfgFilename);
+ const config = Configuration.load(cfgFilename);
+ const bc: FakeBankConfig = {
+ currency: config.getString("taler", "currency").required(),
+ httpPort: config.getNumber("bank", "http_port").required(),
+ };
+ return new FakeBankService(gc, bc, cfgFilename);
+ }
+
+ static async create(
+ gc: GlobalTestState,
+ bc: FakeBankConfig,
+ ): Promise<FakeBankService> {
+ const config = new Configuration();
+ setTalerPaths(config, gc.testDir + "/talerhome");
+ config.setString("taler", "currency", bc.currency);
+ config.setString("bank", "http_port", `${bc.httpPort}`);
+ const cfgFilename = gc.testDir + "/bank.conf";
+ config.write(cfgFilename);
+ return new FakeBankService(gc, bc, cfgFilename);
+ }
+
+ get baseUrl(): string {
+ return `http://localhost:${this.bankConfig.httpPort}/`;
+ }
+
+ get port() {
+ return this.bankConfig.httpPort;
+ }
+
+ private constructor(
+ private globalTestState: GlobalTestState,
+ private bankConfig: FakeBankConfig,
+ private configFile: string,
+ ) {}
+
+ async start(): Promise<void> {
+ this.proc = this.globalTestState.spawnService(
+ "taler-fakebank-run",
+ ["-c", this.configFile],
+ "fakebank",
+ );
+ }
+
+ async pingUntilAvailable(): Promise<void> {
+ // Fakebank doesn't have "/config", so we ping just "/".
+ const url = `http://localhost:${this.bankConfig.httpPort}/`;
+ await pingProc(this.proc, url, "bank");
+ }
+}
+
export interface BankUser {
username: string;
password: string;
diff --git a/packages/taler-wallet-cli/src/integrationtests/helpers.ts
b/packages/taler-wallet-cli/src/integrationtests/helpers.ts
index 1fdc3678..3b4e1643 100644
--- a/packages/taler-wallet-cli/src/integrationtests/helpers.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/helpers.ts
@@ -353,13 +353,22 @@ export async function makeTestPayment(
const { wallet, merchant } = args;
const instance = args.instance ?? "default";
- const orderResp = await MerchantPrivateApi.createOrder(merchant, instance, {
- order: args.order,
- }, auth);
+ const orderResp = await MerchantPrivateApi.createOrder(
+ merchant,
+ instance,
+ {
+ order: args.order,
+ },
+ auth,
+ );
- let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant,
{
- orderId: orderResp.order_id,
- }, auth);
+ let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
+ merchant,
+ {
+ orderId: orderResp.order_id,
+ },
+ auth,
+ );
t.assertTrue(orderStatus.order_status === "unpaid");
@@ -384,10 +393,14 @@ export async function makeTestPayment(
// Check if payment was successful.
- orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
- orderId: orderResp.order_id,
- instance,
- }, auth);
+ orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
+ merchant,
+ {
+ orderId: orderResp.order_id,
+ instance,
+ },
+ auth,
+ );
t.assertTrue(orderStatus.order_status === "paid");
}
diff --git
a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts
similarity index 50%
copy from
packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
copy to
packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts
index 61361807..bfe29b32 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-fakebank.ts
@@ -17,48 +17,68 @@
/**
* Imports.
*/
-import { GlobalTestState, BankApi } from "./harness";
+import {
+ GlobalTestState,
+ BankApi,
+ WalletCli,
+ setupDb,
+ ExchangeService,
+ FakeBankService,
+} from "./harness";
import { createSimpleTestkudosEnvironment } from "./helpers";
-import { CoreApiResponse } from "@gnu-taler/taler-util";
-import { codecForBalancesResponse } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { CoinConfig, defaultCoinConfig } from "./denomStructures.js";
+import { URL } from "@gnu-taler/taler-util";
/**
* Run test for basic, bank-integrated withdrawal.
*/
-export async function runTestWithdrawalManualTest(t: GlobalTestState) {
+export async function runTestWithdrawalFakebankTest(t: GlobalTestState) {
// Set up test environment
- const {
- wallet,
- bank,
- exchange,
- exchangeBankAccount,
- } = await createSimpleTestkudosEnvironment(t);
+ const db = await setupDb(t);
- // Create a withdrawal operation
-
- const user = await BankApi.createRandomBankUser(bank);
+ const bank = await FakeBankService.create(t, {
+ currency: "TESTKUDOS",
+ httpPort: 8082,
+ });
- let wresp: CoreApiResponse;
+ const exchange = ExchangeService.create(t, {
+ name: "testexchange-1",
+ currency: "TESTKUDOS",
+ httpPort: 8081,
+ database: db.connStr,
+ });
- await wallet.client.call(WalletApiOperation.AddExchange, {
- exchangeBaseUrl: exchange.baseUrl,
+ exchange.addBankAccount("1", {
+ accountName: "exchange",
+ accountPassword: "x",
+ wireGatewayApiBaseUrl: new URL("/exchange/", bank.baseUrl).href,
+ accountPaytoUri: "payto://x-taler-bank/localhost/exchange",
});
+ await bank.start();
+
+ await bank.pingUntilAvailable();
+
+ const coinConfig: CoinConfig[] = defaultCoinConfig.map((x) =>
x("TESTKUDOS"));
+ exchange.addCoinConfigList(coinConfig);
- const wres = await
wallet.client.call(WalletApiOperation.AcceptManualWithdrawal, {
+ await exchange.start();
+ await exchange.pingUntilAvailable();
+
+ console.log("setup done!");
+
+ const wallet = new WalletCli(t);
+
+ await wallet.client.call(WalletApiOperation.AddExchange, {
exchangeBaseUrl: exchange.baseUrl,
- amount: "TESTKUDOS:10",
});
- const reservePub: string = wres.reservePub;
-
- await BankApi.adminAddIncoming(bank, {
- exchangeBankAccount,
+ await wallet.client.call(WalletApiOperation.WithdrawFakebank, {
+ exchange: exchange.baseUrl,
amount: "TESTKUDOS:10",
- debitAccountPayto: user.accountPaytoUri,
- reservePub: reservePub,
+ bank: bank.baseUrl,
});
await exchange.runWirewatchOnce();
@@ -73,4 +93,4 @@ export async function runTestWithdrawalManualTest(t:
GlobalTestState) {
await t.shutdown();
}
-runTestWithdrawalManualTest.suites = ["wallet"];
+runTestWithdrawalFakebankTest.suites = ["wallet"];
diff --git
a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
index 61361807..fe8fd3c5 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-withdrawal-manual.ts
@@ -19,8 +19,6 @@
*/
import { GlobalTestState, BankApi } from "./harness";
import { createSimpleTestkudosEnvironment } from "./helpers";
-import { CoreApiResponse } from "@gnu-taler/taler-util";
-import { codecForBalancesResponse } from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
/**
@@ -40,8 +38,6 @@ export async function runTestWithdrawalManualTest(t:
GlobalTestState) {
const user = await BankApi.createRandomBankUser(bank);
- let wresp: CoreApiResponse;
-
await wallet.client.call(WalletApiOperation.AddExchange, {
exchangeBaseUrl: exchange.baseUrl,
});
diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
index 720dd8b8..bcb0dd27 100644
--- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
@@ -87,6 +87,7 @@ import { runPaymentZeroTest } from "./test-payment-zero.js";
import { runMerchantSpecPublicOrdersTest } from
"./test-merchant-spec-public-orders.js";
import { runExchangeTimetravelTest } from "./test-exchange-timetravel.js";
import { runDenomUnofferedTest } from "./test-denom-unoffered.js";
+import { runTestWithdrawalFakebankTest } from "./test-withdrawal-fakebank.js";
/**
* Test runner.
@@ -154,6 +155,7 @@ const allTests: TestMainFunction[] = [
runRefundTest,
runRevocationTest,
runTestWithdrawalManualTest,
+ runTestWithdrawalFakebankTest,
runTimetravelAutorefreshTest,
runTimetravelWithdrawTest,
runTippingTest,
@@ -340,7 +342,7 @@ export async function runTests(spec: TestRunSpec) {
try {
result = await token.racePromise(resultPromise);
- } catch (e) {
+ } catch (e: any) {
console.error(`test ${testName} timed out`);
if (token.isCancelled) {
result = {
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts
b/packages/taler-wallet-core/src/wallet-api-types.ts
index 75121ed3..c5bf2c8c 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -63,10 +63,14 @@ import {
TransactionsResponse,
WalletBackupContentV1,
WalletCurrencyInfo,
+ WithdrawFakebankRequest,
WithdrawTestBalanceRequest,
WithdrawUriInfoResponse,
} from "@gnu-taler/taler-util";
-import { AddBackupProviderRequest, BackupInfo } from
"./operations/backup/index.js";
+import {
+ AddBackupProviderRequest,
+ BackupInfo,
+} from "./operations/backup/index.js";
import { PendingOperationsResponse } from "./pending-types.js";
export enum WalletApiOperation {
@@ -110,9 +114,14 @@ export enum WalletApiOperation {
CreateDepositGroup = "createDepositGroup",
SetWalletDeviceId = "setWalletDeviceId",
ExportBackupPlain = "exportBackupPlain",
+ WithdrawFakebank = "withdrawFakebank",
}
export type WalletOperations = {
+ [WalletApiOperation.WithdrawFakebank]: {
+ request: WithdrawFakebankRequest;
+ response: {};
+ };
[WalletApiOperation.PreparePayForUri]: {
request: PreparePayRequest;
response: PreparePayResult;
@@ -256,7 +265,7 @@ export type WalletOperations = {
[WalletApiOperation.TestPay]: {
request: TestPayArgs;
response: {};
- }
+ };
};
export type RequestType<
diff --git a/packages/taler-wallet-core/src/wallet.ts
b/packages/taler-wallet-core/src/wallet.ts
index 253a69df..32e3945e 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -38,6 +38,9 @@ import {
Timestamp,
timestampMin,
WalletNotification,
+ codecForWithdrawFakebankRequest,
+ URL,
+ parsePaytoUri,
} from "@gnu-taler/taler-util";
import {
addBackupProvider,
@@ -173,7 +176,10 @@ import {
openPromise,
} from "./util/promiseUtils.js";
import { DbAccess } from "./util/query.js";
-import { HttpRequestLibrary } from "./util/http.js";
+import {
+ HttpRequestLibrary,
+ readSuccessResponseJsonOrThrow,
+} from "./util/http.js";
const builtinAuditors: AuditorTrustRecord[] = [
{
@@ -217,7 +223,12 @@ async function processOnePendingOperation(
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
switch (pending.type) {
case PendingTaskType.ExchangeUpdate:
- await updateExchangeFromUrl(ws, pending.exchangeBaseUrl, undefined,
forceNow);
+ await updateExchangeFromUrl(
+ ws,
+ pending.exchangeBaseUrl,
+ undefined,
+ forceNow,
+ );
break;
case PendingTaskType.Refresh:
await processRefreshGroup(ws, pending.refreshGroupId, forceNow);
@@ -418,7 +429,7 @@ async function fillDefaults(ws: InternalWalletState):
Promise<void> {
}
/**
- * Create a reserve, but do not flag it as confirmed yet.
+ * Create a reserve for a manual withdrawal.
*
* Adds the corresponding exchange as a trusted exchange if it is neither
* audited nor trusted already.
@@ -462,7 +473,11 @@ async function getExchangeTos(
const content = exchangeDetails.termsOfServiceText;
const currentEtag = exchangeDetails.termsOfServiceLastEtag;
const contentType = exchangeDetails.termsOfServiceContentType;
- if (content === undefined || currentEtag === undefined || contentType ===
undefined) {
+ if (
+ content === undefined ||
+ currentEtag === undefined ||
+ contentType === undefined
+ ) {
throw Error("exchange is in invalid state");
}
return {
@@ -688,7 +703,12 @@ async function dispatchRequestInternal(
}
case "addExchange": {
const req = codecForAddExchangeRequest().decode(payload);
- await updateExchangeFromUrl(ws, req.exchangeBaseUrl, undefined,
req.forceUpdate);
+ await updateExchangeFromUrl(
+ ws,
+ req.exchangeBaseUrl,
+ undefined,
+ req.forceUpdate,
+ );
return {};
}
case "listExchanges": {
@@ -700,7 +720,11 @@ async function dispatchRequestInternal(
}
case "getExchangeWithdrawalInfo": {
const req = codecForGetExchangeWithdrawalInfo().decode(payload);
- return await getExchangeWithdrawalInfo(ws, req.exchangeBaseUrl,
req.amount);
+ return await getExchangeWithdrawalInfo(
+ ws,
+ req.exchangeBaseUrl,
+ req.amount,
+ );
}
case "acceptManualWithdrawal": {
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
@@ -748,7 +772,7 @@ async function dispatchRequestInternal(
}
case "getExchangeTos": {
const req = codecForGetExchangeTosRequest().decode(payload);
- return getExchangeTos(ws, req.exchangeBaseUrl , req.acceptedFormat);
+ return getExchangeTos(ws, req.exchangeBaseUrl, req.acceptedFormat);
}
case "retryPendingNow": {
await runPending(ws, true);
@@ -889,6 +913,35 @@ async function dispatchRequestInternal(
};
});
}
+ case "withdrawFakebank": {
+ const req = codecForWithdrawFakebankRequest().decode(payload);
+ const amount = Amounts.parseOrThrow(req.amount);
+ const details = await getWithdrawalDetailsForAmount(
+ ws,
+ req.exchange,
+ amount,
+ );
+ const wres = await acceptManualWithdrawal(ws, req.exchange, amount);
+ const paytoUri = details.paytoUris[0];
+ const pt = parsePaytoUri(paytoUri);
+ if (!pt) {
+ throw Error("failed to parse payto URI");
+ }
+ const components = pt.targetPath.split("/");
+ const creditorAcct = components[components.length - 1];
+ logger.info(`making testbank transfer to '${creditorAcct}''`)
+ const fbReq = await ws.http.postJson(
+ new URL(`${creditorAcct}/admin/add-incoming`, req.bank).href,
+ {
+ amount: Amounts.stringify(amount),
+ reserve_pub: wres.reservePub,
+ debit_account: "payto://x-taler-bank/localhost/testdebtor",
+ },
+ );
+ const fbResp = await readSuccessResponseJsonOrThrow(fbReq,
codecForAny());
+ logger.info(`started fakebank withdrawal: ${j2s(fbResp)}`);
+ return {};
+ }
}
throw OperationFailedError.fromCode(
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
@@ -916,7 +969,7 @@ export async function handleCoreApiRequest(
id,
result,
};
- } catch (e) {
+ } catch (e: any) {
if (
e instanceof OperationFailedError ||
e instanceof OperationFailedAndReportedError
@@ -928,6 +981,10 @@ export async function handleCoreApiRequest(
error: e.operationError,
};
} else {
+ try {
+ logger.error("Caught unexpected exception:");
+ logger.error(e.stack);
+ } catch (e) {}
return {
type: "error",
operation,
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-wallet-core] branch master updated: implement fakebank withdrawal,
gnunet <=