implement fakebank withdrawal
This commit is contained in:
parent
6f4c0a6fb2
commit
c532648694
@ -590,11 +590,11 @@ export interface GetExchangeTosResult {
|
|||||||
* if any.
|
* if any.
|
||||||
*/
|
*/
|
||||||
acceptedEtag: string | undefined;
|
acceptedEtag: string | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepted content type
|
* Accepted content type
|
||||||
*/
|
*/
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TestPayArgs {
|
export interface TestPayArgs {
|
||||||
@ -658,9 +658,9 @@ export interface GetExchangeTosRequest {
|
|||||||
|
|
||||||
export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
|
export const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
|
||||||
buildCodecForObject<GetExchangeTosRequest>()
|
buildCodecForObject<GetExchangeTosRequest>()
|
||||||
.property("exchangeBaseUrl", codecForString())
|
.property("exchangeBaseUrl", codecForString())
|
||||||
.property("acceptedFormat", codecOptional(codecForList(codecForString())))
|
.property("acceptedFormat", codecOptional(codecForList(codecForString())))
|
||||||
.build("GetExchangeTosRequest");
|
.build("GetExchangeTosRequest");
|
||||||
|
|
||||||
export interface AcceptManualWithdrawalRequest {
|
export interface AcceptManualWithdrawalRequest {
|
||||||
exchangeBaseUrl: string;
|
exchangeBaseUrl: string;
|
||||||
@ -734,7 +734,10 @@ export const codecForGetExchangeWithdrawalInfo = (): Codec<GetExchangeWithdrawal
|
|||||||
buildCodecForObject<GetExchangeWithdrawalInfo>()
|
buildCodecForObject<GetExchangeWithdrawalInfo>()
|
||||||
.property("exchangeBaseUrl", codecForString())
|
.property("exchangeBaseUrl", codecForString())
|
||||||
.property("amount", codecForAmountJson())
|
.property("amount", codecForAmountJson())
|
||||||
.property("tosAcceptedFormat", codecOptional(codecForList(codecForString())))
|
.property(
|
||||||
|
"tosAcceptedFormat",
|
||||||
|
codecOptional(codecForList(codecForString())),
|
||||||
|
)
|
||||||
.build("GetExchangeWithdrawalInfo");
|
.build("GetExchangeWithdrawalInfo");
|
||||||
|
|
||||||
export interface AbortProposalRequest {
|
export interface AbortProposalRequest {
|
||||||
@ -1029,3 +1032,16 @@ export const codecForSetWalletDeviceIdRequest = (): Codec<SetWalletDeviceIdReque
|
|||||||
buildCodecForObject<SetWalletDeviceIdRequest>()
|
buildCodecForObject<SetWalletDeviceIdRequest>()
|
||||||
.property("walletDeviceId", codecForString())
|
.property("walletDeviceId", codecForString())
|
||||||
.build("SetWalletDeviceIdRequest");
|
.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");
|
||||||
|
@ -634,6 +634,29 @@ const advancedCli = walletCli.subcommand("advancedArgs", "advanced", {
|
|||||||
"Subcommands for advanced operations (only use if you know what you're doing!).",
|
"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
|
advancedCli
|
||||||
.subcommand("manualWithdrawalDetails", "manual-withdrawal-details", {
|
.subcommand("manualWithdrawalDetails", "manual-withdrawal-details", {
|
||||||
help: "Query withdrawal fees.",
|
help: "Query withdrawal fees.",
|
||||||
@ -1064,6 +1087,5 @@ export function main() {
|
|||||||
logger.warn("Allowing withdrawal of late denominations for debugging");
|
logger.warn("Allowing withdrawal of late denominations for debugging");
|
||||||
walletCoreDebugFlags.denomselAllowLate = true;
|
walletCoreDebugFlags.denomselAllowLate = true;
|
||||||
}
|
}
|
||||||
logger.trace(`running wallet-cli with`, process.argv);
|
|
||||||
walletCli.run();
|
walletCli.run();
|
||||||
}
|
}
|
||||||
|
@ -395,6 +395,11 @@ export interface BankConfig {
|
|||||||
maxDebt?: string;
|
maxDebt?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FakeBankConfig {
|
||||||
|
currency: string;
|
||||||
|
httpPort: number;
|
||||||
|
}
|
||||||
|
|
||||||
function setTalerPaths(config: Configuration, home: string) {
|
function setTalerPaths(config: Configuration, home: string) {
|
||||||
config.setString("paths", "taler_home", home);
|
config.setString("paths", "taler_home", home);
|
||||||
// We need to make sure that the path of taler_runtime_dir isn't too long,
|
// 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 {
|
export interface BankUser {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
@ -353,13 +353,22 @@ export async function makeTestPayment(
|
|||||||
const { wallet, merchant } = args;
|
const { wallet, merchant } = args;
|
||||||
const instance = args.instance ?? "default";
|
const instance = args.instance ?? "default";
|
||||||
|
|
||||||
const orderResp = await MerchantPrivateApi.createOrder(merchant, instance, {
|
const orderResp = await MerchantPrivateApi.createOrder(
|
||||||
order: args.order,
|
merchant,
|
||||||
}, auth);
|
instance,
|
||||||
|
{
|
||||||
|
order: args.order,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
|
let orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
|
||||||
orderId: orderResp.order_id,
|
merchant,
|
||||||
}, auth);
|
{
|
||||||
|
orderId: orderResp.order_id,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
t.assertTrue(orderStatus.order_status === "unpaid");
|
t.assertTrue(orderStatus.order_status === "unpaid");
|
||||||
|
|
||||||
@ -384,10 +393,14 @@ export async function makeTestPayment(
|
|||||||
|
|
||||||
// Check if payment was successful.
|
// Check if payment was successful.
|
||||||
|
|
||||||
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(merchant, {
|
orderStatus = await MerchantPrivateApi.queryPrivateOrderStatus(
|
||||||
orderId: orderResp.order_id,
|
merchant,
|
||||||
instance,
|
{
|
||||||
}, auth);
|
orderId: orderResp.order_id,
|
||||||
|
instance,
|
||||||
|
},
|
||||||
|
auth,
|
||||||
|
);
|
||||||
|
|
||||||
t.assertTrue(orderStatus.order_status === "paid");
|
t.assertTrue(orderStatus.order_status === "paid");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
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 {
|
||||||
|
GlobalTestState,
|
||||||
|
BankApi,
|
||||||
|
WalletCli,
|
||||||
|
setupDb,
|
||||||
|
ExchangeService,
|
||||||
|
FakeBankService,
|
||||||
|
} from "./harness";
|
||||||
|
import { createSimpleTestkudosEnvironment } from "./helpers";
|
||||||
|
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 runTestWithdrawalFakebankTest(t: GlobalTestState) {
|
||||||
|
// Set up test environment
|
||||||
|
|
||||||
|
const db = await setupDb(t);
|
||||||
|
|
||||||
|
const bank = await FakeBankService.create(t, {
|
||||||
|
currency: "TESTKUDOS",
|
||||||
|
httpPort: 8082,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exchange = ExchangeService.create(t, {
|
||||||
|
name: "testexchange-1",
|
||||||
|
currency: "TESTKUDOS",
|
||||||
|
httpPort: 8081,
|
||||||
|
database: db.connStr,
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
await exchange.start();
|
||||||
|
await exchange.pingUntilAvailable();
|
||||||
|
|
||||||
|
console.log("setup done!");
|
||||||
|
|
||||||
|
const wallet = new WalletCli(t);
|
||||||
|
|
||||||
|
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||||
|
exchangeBaseUrl: exchange.baseUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
await wallet.client.call(WalletApiOperation.WithdrawFakebank, {
|
||||||
|
exchange: exchange.baseUrl,
|
||||||
|
amount: "TESTKUDOS:10",
|
||||||
|
bank: bank.baseUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
await exchange.runWirewatchOnce();
|
||||||
|
|
||||||
|
await wallet.runUntilDone();
|
||||||
|
|
||||||
|
// Check balance
|
||||||
|
|
||||||
|
const balResp = await wallet.client.call(WalletApiOperation.GetBalances, {});
|
||||||
|
t.assertAmountEquals("TESTKUDOS:9.72", balResp.balances[0].available);
|
||||||
|
|
||||||
|
await t.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
runTestWithdrawalFakebankTest.suites = ["wallet"];
|
@ -19,8 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
import { GlobalTestState, BankApi } from "./harness";
|
import { GlobalTestState, BankApi } from "./harness";
|
||||||
import { createSimpleTestkudosEnvironment } from "./helpers";
|
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 { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,8 +38,6 @@ export async function runTestWithdrawalManualTest(t: GlobalTestState) {
|
|||||||
|
|
||||||
const user = await BankApi.createRandomBankUser(bank);
|
const user = await BankApi.createRandomBankUser(bank);
|
||||||
|
|
||||||
let wresp: CoreApiResponse;
|
|
||||||
|
|
||||||
await wallet.client.call(WalletApiOperation.AddExchange, {
|
await wallet.client.call(WalletApiOperation.AddExchange, {
|
||||||
exchangeBaseUrl: exchange.baseUrl,
|
exchangeBaseUrl: exchange.baseUrl,
|
||||||
});
|
});
|
||||||
|
@ -87,6 +87,7 @@ import { runPaymentZeroTest } from "./test-payment-zero.js";
|
|||||||
import { runMerchantSpecPublicOrdersTest } from "./test-merchant-spec-public-orders.js";
|
import { runMerchantSpecPublicOrdersTest } from "./test-merchant-spec-public-orders.js";
|
||||||
import { runExchangeTimetravelTest } from "./test-exchange-timetravel.js";
|
import { runExchangeTimetravelTest } from "./test-exchange-timetravel.js";
|
||||||
import { runDenomUnofferedTest } from "./test-denom-unoffered.js";
|
import { runDenomUnofferedTest } from "./test-denom-unoffered.js";
|
||||||
|
import { runTestWithdrawalFakebankTest } from "./test-withdrawal-fakebank.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test runner.
|
* Test runner.
|
||||||
@ -154,6 +155,7 @@ const allTests: TestMainFunction[] = [
|
|||||||
runRefundTest,
|
runRefundTest,
|
||||||
runRevocationTest,
|
runRevocationTest,
|
||||||
runTestWithdrawalManualTest,
|
runTestWithdrawalManualTest,
|
||||||
|
runTestWithdrawalFakebankTest,
|
||||||
runTimetravelAutorefreshTest,
|
runTimetravelAutorefreshTest,
|
||||||
runTimetravelWithdrawTest,
|
runTimetravelWithdrawTest,
|
||||||
runTippingTest,
|
runTippingTest,
|
||||||
@ -340,7 +342,7 @@ export async function runTests(spec: TestRunSpec) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
result = await token.racePromise(resultPromise);
|
result = await token.racePromise(resultPromise);
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.error(`test ${testName} timed out`);
|
console.error(`test ${testName} timed out`);
|
||||||
if (token.isCancelled) {
|
if (token.isCancelled) {
|
||||||
result = {
|
result = {
|
||||||
|
@ -63,10 +63,14 @@ import {
|
|||||||
TransactionsResponse,
|
TransactionsResponse,
|
||||||
WalletBackupContentV1,
|
WalletBackupContentV1,
|
||||||
WalletCurrencyInfo,
|
WalletCurrencyInfo,
|
||||||
|
WithdrawFakebankRequest,
|
||||||
WithdrawTestBalanceRequest,
|
WithdrawTestBalanceRequest,
|
||||||
WithdrawUriInfoResponse,
|
WithdrawUriInfoResponse,
|
||||||
} from "@gnu-taler/taler-util";
|
} 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";
|
import { PendingOperationsResponse } from "./pending-types.js";
|
||||||
|
|
||||||
export enum WalletApiOperation {
|
export enum WalletApiOperation {
|
||||||
@ -110,9 +114,14 @@ export enum WalletApiOperation {
|
|||||||
CreateDepositGroup = "createDepositGroup",
|
CreateDepositGroup = "createDepositGroup",
|
||||||
SetWalletDeviceId = "setWalletDeviceId",
|
SetWalletDeviceId = "setWalletDeviceId",
|
||||||
ExportBackupPlain = "exportBackupPlain",
|
ExportBackupPlain = "exportBackupPlain",
|
||||||
|
WithdrawFakebank = "withdrawFakebank",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WalletOperations = {
|
export type WalletOperations = {
|
||||||
|
[WalletApiOperation.WithdrawFakebank]: {
|
||||||
|
request: WithdrawFakebankRequest;
|
||||||
|
response: {};
|
||||||
|
};
|
||||||
[WalletApiOperation.PreparePayForUri]: {
|
[WalletApiOperation.PreparePayForUri]: {
|
||||||
request: PreparePayRequest;
|
request: PreparePayRequest;
|
||||||
response: PreparePayResult;
|
response: PreparePayResult;
|
||||||
@ -256,7 +265,7 @@ export type WalletOperations = {
|
|||||||
[WalletApiOperation.TestPay]: {
|
[WalletApiOperation.TestPay]: {
|
||||||
request: TestPayArgs;
|
request: TestPayArgs;
|
||||||
response: {};
|
response: {};
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RequestType<
|
export type RequestType<
|
||||||
|
@ -38,6 +38,9 @@ import {
|
|||||||
Timestamp,
|
Timestamp,
|
||||||
timestampMin,
|
timestampMin,
|
||||||
WalletNotification,
|
WalletNotification,
|
||||||
|
codecForWithdrawFakebankRequest,
|
||||||
|
URL,
|
||||||
|
parsePaytoUri,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
addBackupProvider,
|
addBackupProvider,
|
||||||
@ -173,7 +176,10 @@ import {
|
|||||||
openPromise,
|
openPromise,
|
||||||
} from "./util/promiseUtils.js";
|
} from "./util/promiseUtils.js";
|
||||||
import { DbAccess } from "./util/query.js";
|
import { DbAccess } from "./util/query.js";
|
||||||
import { HttpRequestLibrary } from "./util/http.js";
|
import {
|
||||||
|
HttpRequestLibrary,
|
||||||
|
readSuccessResponseJsonOrThrow,
|
||||||
|
} from "./util/http.js";
|
||||||
|
|
||||||
const builtinAuditors: AuditorTrustRecord[] = [
|
const builtinAuditors: AuditorTrustRecord[] = [
|
||||||
{
|
{
|
||||||
@ -217,7 +223,12 @@ async function processOnePendingOperation(
|
|||||||
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
|
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
|
||||||
switch (pending.type) {
|
switch (pending.type) {
|
||||||
case PendingTaskType.ExchangeUpdate:
|
case PendingTaskType.ExchangeUpdate:
|
||||||
await updateExchangeFromUrl(ws, pending.exchangeBaseUrl, undefined, forceNow);
|
await updateExchangeFromUrl(
|
||||||
|
ws,
|
||||||
|
pending.exchangeBaseUrl,
|
||||||
|
undefined,
|
||||||
|
forceNow,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case PendingTaskType.Refresh:
|
case PendingTaskType.Refresh:
|
||||||
await processRefreshGroup(ws, pending.refreshGroupId, forceNow);
|
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
|
* Adds the corresponding exchange as a trusted exchange if it is neither
|
||||||
* audited nor trusted already.
|
* audited nor trusted already.
|
||||||
@ -462,7 +473,11 @@ async function getExchangeTos(
|
|||||||
const content = exchangeDetails.termsOfServiceText;
|
const content = exchangeDetails.termsOfServiceText;
|
||||||
const currentEtag = exchangeDetails.termsOfServiceLastEtag;
|
const currentEtag = exchangeDetails.termsOfServiceLastEtag;
|
||||||
const contentType = exchangeDetails.termsOfServiceContentType;
|
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");
|
throw Error("exchange is in invalid state");
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -688,7 +703,12 @@ async function dispatchRequestInternal(
|
|||||||
}
|
}
|
||||||
case "addExchange": {
|
case "addExchange": {
|
||||||
const req = codecForAddExchangeRequest().decode(payload);
|
const req = codecForAddExchangeRequest().decode(payload);
|
||||||
await updateExchangeFromUrl(ws, req.exchangeBaseUrl, undefined, req.forceUpdate);
|
await updateExchangeFromUrl(
|
||||||
|
ws,
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
undefined,
|
||||||
|
req.forceUpdate,
|
||||||
|
);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
case "listExchanges": {
|
case "listExchanges": {
|
||||||
@ -700,7 +720,11 @@ async function dispatchRequestInternal(
|
|||||||
}
|
}
|
||||||
case "getExchangeWithdrawalInfo": {
|
case "getExchangeWithdrawalInfo": {
|
||||||
const req = codecForGetExchangeWithdrawalInfo().decode(payload);
|
const req = codecForGetExchangeWithdrawalInfo().decode(payload);
|
||||||
return await getExchangeWithdrawalInfo(ws, req.exchangeBaseUrl, req.amount);
|
return await getExchangeWithdrawalInfo(
|
||||||
|
ws,
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
req.amount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case "acceptManualWithdrawal": {
|
case "acceptManualWithdrawal": {
|
||||||
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
|
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
|
||||||
@ -748,7 +772,7 @@ async function dispatchRequestInternal(
|
|||||||
}
|
}
|
||||||
case "getExchangeTos": {
|
case "getExchangeTos": {
|
||||||
const req = codecForGetExchangeTosRequest().decode(payload);
|
const req = codecForGetExchangeTosRequest().decode(payload);
|
||||||
return getExchangeTos(ws, req.exchangeBaseUrl , req.acceptedFormat);
|
return getExchangeTos(ws, req.exchangeBaseUrl, req.acceptedFormat);
|
||||||
}
|
}
|
||||||
case "retryPendingNow": {
|
case "retryPendingNow": {
|
||||||
await runPending(ws, true);
|
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(
|
throw OperationFailedError.fromCode(
|
||||||
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
|
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
|
||||||
@ -916,7 +969,7 @@ export async function handleCoreApiRequest(
|
|||||||
id,
|
id,
|
||||||
result,
|
result,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
if (
|
if (
|
||||||
e instanceof OperationFailedError ||
|
e instanceof OperationFailedError ||
|
||||||
e instanceof OperationFailedAndReportedError
|
e instanceof OperationFailedAndReportedError
|
||||||
@ -928,6 +981,10 @@ export async function handleCoreApiRequest(
|
|||||||
error: e.operationError,
|
error: e.operationError,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
try {
|
||||||
|
logger.error("Caught unexpected exception:");
|
||||||
|
logger.error(e.stack);
|
||||||
|
} catch (e) {}
|
||||||
return {
|
return {
|
||||||
type: "error",
|
type: "error",
|
||||||
operation,
|
operation,
|
||||||
|
Loading…
Reference in New Issue
Block a user