implement common wallet-core API handler
This commit is contained in:
parent
80433b9399
commit
56ece296e0
3079
src/TalerErrorCode.ts
Normal file
3079
src/TalerErrorCode.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -38,6 +38,7 @@ import {
|
|||||||
WALLET_MERCHANT_PROTOCOL_VERSION,
|
WALLET_MERCHANT_PROTOCOL_VERSION,
|
||||||
} from "../operations/versions";
|
} from "../operations/versions";
|
||||||
import { Amounts } from "../util/amounts";
|
import { Amounts } from "../util/amounts";
|
||||||
|
import { handleCoreApiRequest } from "../walletCoreApiHandler";
|
||||||
|
|
||||||
// @ts-ignore: special built-in module
|
// @ts-ignore: special built-in module
|
||||||
//import akono = require("akono");
|
//import akono = require("akono");
|
||||||
@ -168,88 +169,8 @@ class AndroidWalletMessageHandler {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "getTransactions": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getTransactions(args);
|
|
||||||
}
|
|
||||||
case "abortProposal": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
if (typeof args.proposalId !== "string") {
|
|
||||||
throw Error("propsalId must be a string");
|
|
||||||
}
|
|
||||||
return await wallet.refuseProposal(args.proposalId);
|
|
||||||
}
|
|
||||||
case "getBalances": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getBalances();
|
|
||||||
}
|
|
||||||
case "getPendingOperations": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getPendingOperations();
|
|
||||||
}
|
|
||||||
case "listExchanges": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getExchanges();
|
|
||||||
}
|
|
||||||
case "addExchange": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
await wallet.updateExchangeFromUrl(args.exchangeBaseUrl);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
case "getWithdrawalDetailsForAmount": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getWithdrawalDetailsForAmount(
|
|
||||||
args.exchangeBaseUrl,
|
|
||||||
args.amount,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "withdrawTestkudos": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
try {
|
|
||||||
await withdrawTestBalance(wallet);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("error during withdrawTestBalance", e);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
case "getHistory": {
|
case "getHistory": {
|
||||||
const wallet = await this.wp.promise;
|
return [];
|
||||||
return await wallet.getHistory();
|
|
||||||
}
|
|
||||||
case "getExchangeTos": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
const exchangeBaseUrl = args.exchangeBaseUrl;
|
|
||||||
return wallet.getExchangeTos(exchangeBaseUrl);
|
|
||||||
}
|
|
||||||
case "setExchangeTosAccepted": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
await wallet.acceptExchangeTermsOfService(
|
|
||||||
args.exchangeBaseUrl,
|
|
||||||
args.acceptedEtag,
|
|
||||||
);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
case "retryPendingNow": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
await wallet.runPending(true);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
case "preparePay": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.preparePayForUri(args.url);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "confirmPay": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.confirmPay(args.proposalId, args.sessionId);
|
|
||||||
}
|
|
||||||
case "acceptManualWithdrawal": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
const res = await wallet.acceptManualWithdrawal(
|
|
||||||
args.exchangeBaseUrl,
|
|
||||||
Amounts.parseOrThrow(args.amount),
|
|
||||||
);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
case "startTunnel": {
|
case "startTunnel": {
|
||||||
// this.httpLib.useNfcTunnel = true;
|
// this.httpLib.useNfcTunnel = true;
|
||||||
@ -263,31 +184,6 @@ class AndroidWalletMessageHandler {
|
|||||||
// httpLib.handleTunnelResponse(msg.args);
|
// httpLib.handleTunnelResponse(msg.args);
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
case "getWithdrawDetailsForUri": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.getWithdrawDetailsForUri(
|
|
||||||
args.talerWithdrawUri,
|
|
||||||
args.selectedExchange,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "applyRefund": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.applyRefund(args.talerRefundUri);
|
|
||||||
}
|
|
||||||
case "acceptExchangeTermsOfService": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.acceptExchangeTermsOfService(
|
|
||||||
args.exchangeBaseUrl,
|
|
||||||
args.etag,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "acceptWithdrawal": {
|
|
||||||
const wallet = await this.wp.promise;
|
|
||||||
return await wallet.acceptWithdrawal(
|
|
||||||
args.talerWithdrawUri,
|
|
||||||
args.selectedExchange,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "reset": {
|
case "reset": {
|
||||||
const oldArgs = this.walletArgs;
|
const oldArgs = this.walletArgs;
|
||||||
this.walletArgs = { ...oldArgs };
|
this.walletArgs = { ...oldArgs };
|
||||||
@ -312,8 +208,11 @@ class AndroidWalletMessageHandler {
|
|||||||
this.wp.resolve(w);
|
this.wp.resolve(w);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
throw Error(`operation "${operation}" not understood`);
|
const wallet = await this.wp.promise;
|
||||||
|
return await handleCoreApiRequest(wallet, operation, id, args);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,23 +199,22 @@ walletCli
|
|||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
walletCli
|
||||||
.subcommand("api", "balance", { help: "Call the wallet-core API directly." })
|
.subcommand("api", "api", { help: "Call the wallet-core API directly." })
|
||||||
.requiredArgument("operation", clk.STRING)
|
.requiredArgument("operation", clk.STRING)
|
||||||
.requiredArgument("request", clk.STRING)
|
.requiredArgument("request", clk.STRING)
|
||||||
.action(async (args) => {
|
.action(async (args) => {
|
||||||
await withWallet(args, async (wallet) => {
|
await withWallet(args, async (wallet) => {
|
||||||
let requestJson;
|
let requestJson;
|
||||||
try {
|
try {
|
||||||
requestJson = JSON.parse(args.api.operation);
|
requestJson = JSON.parse(args.api.request);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("malformed request");
|
console.error("Invalid JSON");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const resp = await handleCoreApiRequest(
|
const resp = await handleCoreApiRequest(
|
||||||
wallet,
|
wallet,
|
||||||
args.api.operation,
|
args.api.operation,
|
||||||
1,
|
"reqid-1",
|
||||||
requestJson,
|
requestJson,
|
||||||
);
|
);
|
||||||
console.log(JSON.stringify(resp, undefined, 2));
|
console.log(JSON.stringify(resp, undefined, 2));
|
||||||
|
@ -51,6 +51,9 @@ import {
|
|||||||
readSuccessResponseJsonOrThrow,
|
readSuccessResponseJsonOrThrow,
|
||||||
readSuccessResponseTextOrThrow,
|
readSuccessResponseTextOrThrow,
|
||||||
} from "../util/http";
|
} from "../util/http";
|
||||||
|
import { Logger } from "../util/logging";
|
||||||
|
|
||||||
|
const logger = new Logger("exchanges.ts");
|
||||||
|
|
||||||
async function denominationRecordFromKeys(
|
async function denominationRecordFromKeys(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
@ -197,7 +200,7 @@ async function updateExchangeWithKeys(
|
|||||||
// Handle recoup
|
// Handle recoup
|
||||||
const recoupDenomList = exchangeKeysJson.recoup ?? [];
|
const recoupDenomList = exchangeKeysJson.recoup ?? [];
|
||||||
const newlyRevokedCoinPubs: string[] = [];
|
const newlyRevokedCoinPubs: string[] = [];
|
||||||
console.log("recoup list from exchange", recoupDenomList);
|
logger.trace("recoup list from exchange", recoupDenomList);
|
||||||
for (const recoupInfo of recoupDenomList) {
|
for (const recoupInfo of recoupDenomList) {
|
||||||
const oldDenom = await tx.getIndexed(
|
const oldDenom = await tx.getIndexed(
|
||||||
Stores.denominations.denomPubHashIndex,
|
Stores.denominations.denomPubHashIndex,
|
||||||
@ -354,7 +357,7 @@ async function updateExchangeWithWireInfo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const a of wireInfo.accounts) {
|
for (const a of wireInfo.accounts) {
|
||||||
console.log("validating exchange acct");
|
logger.trace("validating exchange acct");
|
||||||
const isValid = await ws.cryptoApi.isValidWireAccount(
|
const isValid = await ws.cryptoApi.isValidWireAccount(
|
||||||
a.payto_uri,
|
a.payto_uri,
|
||||||
a.master_sig,
|
a.master_sig,
|
||||||
|
@ -440,11 +440,8 @@ async function incrementReserveRetry(
|
|||||||
if (!r.retryInfo) {
|
if (!r.retryInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("updating retry info");
|
|
||||||
console.log("before", r.retryInfo);
|
|
||||||
r.retryInfo.retryCounter++;
|
r.retryInfo.retryCounter++;
|
||||||
updateRetryInfoTimeout(r.retryInfo);
|
updateRetryInfoTimeout(r.retryInfo);
|
||||||
console.log("after", r.retryInfo);
|
|
||||||
r.lastError = err;
|
r.lastError = err;
|
||||||
await tx.put(Stores.reserves, r);
|
await tx.put(Stores.reserves, r);
|
||||||
});
|
});
|
||||||
@ -528,16 +525,10 @@ async function updateReserve(
|
|||||||
reserveInfo.history,
|
reserveInfo.history,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(
|
|
||||||
"reconciled history:",
|
|
||||||
JSON.stringify(reconciled, undefined, 2),
|
|
||||||
);
|
|
||||||
|
|
||||||
const summary = summarizeReserveHistory(
|
const summary = summarizeReserveHistory(
|
||||||
reconciled.updatedLocalHistory,
|
reconciled.updatedLocalHistory,
|
||||||
currency,
|
currency,
|
||||||
);
|
);
|
||||||
console.log("summary", summary);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
reconciled.newAddedItems.length + reconciled.newMatchedItems.length !=
|
reconciled.newAddedItems.length + reconciled.newMatchedItems.length !=
|
||||||
@ -765,7 +756,7 @@ async function depleteReserve(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (newWithdrawalGroup) {
|
if (newWithdrawalGroup) {
|
||||||
console.log("processing new withdraw group");
|
logger.trace("processing new withdraw group");
|
||||||
ws.notify({
|
ws.notify({
|
||||||
type: NotificationType.WithdrawGroupCreated,
|
type: NotificationType.WithdrawGroupCreated,
|
||||||
withdrawalGroupId: newWithdrawalGroup.withdrawalGroupId,
|
withdrawalGroupId: newWithdrawalGroup.withdrawalGroupId,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
import { Timestamp } from "../util/time";
|
import { Timestamp } from "../util/time";
|
||||||
import { AmountString, Product } from "./talerTypes";
|
import { AmountString, Product } from "./talerTypes";
|
||||||
|
import { Codec, makeCodecForObject, makeCodecOptional, codecForString } from "../util/codec";
|
||||||
|
|
||||||
export interface TransactionsRequest {
|
export interface TransactionsRequest {
|
||||||
/**
|
/**
|
||||||
@ -300,3 +301,10 @@ interface TransactionRefresh extends TransactionCommon {
|
|||||||
// Amount that will be paid as fees for the refresh
|
// Amount that will be paid as fees for the refresh
|
||||||
amountEffective: AmountString;
|
amountEffective: AmountString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const codecForTransactionsRequest = (): Codec<TransactionsRequest> =>
|
||||||
|
makeCodecForObject<TransactionsRequest>()
|
||||||
|
.property("currency", makeCodecOptional(codecForString))
|
||||||
|
.property("search", makeCodecOptional(codecForString))
|
||||||
|
.build("TransactionsRequest");
|
@ -25,6 +25,9 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { Duration } from "./time";
|
import { Duration } from "./time";
|
||||||
|
import { Logger } from "./logging";
|
||||||
|
|
||||||
|
const logger = new Logger("timer.ts");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancelable timer.
|
* Cancelable timer.
|
||||||
@ -119,7 +122,7 @@ export class TimerGroup {
|
|||||||
|
|
||||||
after(delayMs: number, callback: () => void): TimerHandle {
|
after(delayMs: number, callback: () => void): TimerHandle {
|
||||||
if (this.stopped) {
|
if (this.stopped) {
|
||||||
console.warn("dropping timer since timer group is stopped");
|
logger.warn("dropping timer since timer group is stopped");
|
||||||
return nullTimerHandle;
|
return nullTimerHandle;
|
||||||
}
|
}
|
||||||
const h = after(delayMs, callback);
|
const h = after(delayMs, callback);
|
||||||
@ -138,7 +141,7 @@ export class TimerGroup {
|
|||||||
|
|
||||||
every(delayMs: number, callback: () => void): TimerHandle {
|
every(delayMs: number, callback: () => void): TimerHandle {
|
||||||
if (this.stopped) {
|
if (this.stopped) {
|
||||||
console.warn("dropping timer since timer group is stopped");
|
logger.warn("dropping timer since timer group is stopped");
|
||||||
return nullTimerHandle;
|
return nullTimerHandle;
|
||||||
}
|
}
|
||||||
const h = every(delayMs, callback);
|
const h = every(delayMs, callback);
|
||||||
|
@ -195,7 +195,7 @@ export class Wallet {
|
|||||||
pending: PendingOperationInfo,
|
pending: PendingOperationInfo,
|
||||||
forceNow = false,
|
forceNow = false,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
console.log("running pending", pending);
|
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
|
||||||
switch (pending.type) {
|
switch (pending.type) {
|
||||||
case PendingOperationType.Bug:
|
case PendingOperationType.Bug:
|
||||||
// Nothing to do, will just be displayed to the user
|
// Nothing to do, will just be displayed to the user
|
||||||
@ -552,15 +552,6 @@ export class Wallet {
|
|||||||
return await this.db.get(Stores.exchanges, exchangeBaseUrl);
|
return await this.db.get(Stores.exchanges, exchangeBaseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrive the full event history for this wallet.
|
|
||||||
*/
|
|
||||||
async getHistory(
|
|
||||||
historyQuery?: any[],
|
|
||||||
): Promise<{ history: any[] }> {
|
|
||||||
return { history: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPendingOperations({ onlyDue = false } = {}): Promise<
|
async getPendingOperations({ onlyDue = false } = {}): Promise<
|
||||||
PendingOperationsResponse
|
PendingOperationsResponse
|
||||||
> {
|
> {
|
||||||
|
295
src/walletCoreApiHandler.ts
Normal file
295
src/walletCoreApiHandler.ts
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Wallet } from "./wallet";
|
||||||
|
import {
|
||||||
|
OperationFailedError,
|
||||||
|
OperationFailedAndReportedError,
|
||||||
|
makeErrorDetails,
|
||||||
|
} from "./operations/errors";
|
||||||
|
import { TalerErrorCode } from "./TalerErrorCode";
|
||||||
|
import { withdrawTestBalance } from "./headless/helpers";
|
||||||
|
import { codecForTransactionsRequest } from "./types/transactions";
|
||||||
|
import {
|
||||||
|
makeCodecForObject,
|
||||||
|
codecForString,
|
||||||
|
Codec,
|
||||||
|
makeCodecOptional,
|
||||||
|
} from "./util/codec";
|
||||||
|
import { Amounts } from "./util/amounts";
|
||||||
|
|
||||||
|
interface AddExchangeRequest {
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForAddExchangeRequest = (): Codec<AddExchangeRequest> =>
|
||||||
|
makeCodecForObject<AddExchangeRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.build("AddExchangeRequest");
|
||||||
|
|
||||||
|
interface GetExchangeTosRequest {
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForGetExchangeTosRequest = (): Codec<GetExchangeTosRequest> =>
|
||||||
|
makeCodecForObject<GetExchangeTosRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.build("GetExchangeTosRequest");
|
||||||
|
|
||||||
|
interface AcceptManualWithdrawalRequest {
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
amount: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForAcceptManualWithdrawalRequet = (): Codec<
|
||||||
|
AcceptManualWithdrawalRequest
|
||||||
|
> =>
|
||||||
|
makeCodecForObject<AcceptManualWithdrawalRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.property("amount", codecForString)
|
||||||
|
.build("AcceptManualWithdrawalRequest");
|
||||||
|
|
||||||
|
interface GetWithdrawalDetailsForAmountRequest {
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
amount: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AcceptBankIntegratedWithdrawalRequest {
|
||||||
|
talerWithdrawUri: string;
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForAcceptBankIntegratedWithdrawalRequest = (): Codec<
|
||||||
|
AcceptBankIntegratedWithdrawalRequest
|
||||||
|
> =>
|
||||||
|
makeCodecForObject<AcceptBankIntegratedWithdrawalRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.property("talerWithdrawUri", codecForString)
|
||||||
|
.build("AcceptBankIntegratedWithdrawalRequest");
|
||||||
|
|
||||||
|
const codecForGetWithdrawalDetailsForAmountRequest = (): Codec<
|
||||||
|
GetWithdrawalDetailsForAmountRequest
|
||||||
|
> =>
|
||||||
|
makeCodecForObject<GetWithdrawalDetailsForAmountRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.property("amount", codecForString)
|
||||||
|
.build("GetWithdrawalDetailsForAmountRequest");
|
||||||
|
|
||||||
|
interface AcceptExchangeTosRequest {
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
etag: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForAcceptExchangeTosRequest = (): Codec<AcceptExchangeTosRequest> =>
|
||||||
|
makeCodecForObject<AcceptExchangeTosRequest>()
|
||||||
|
.property("exchangeBaseUrl", codecForString)
|
||||||
|
.property("etag", codecForString)
|
||||||
|
.build("AcceptExchangeTosRequest");
|
||||||
|
|
||||||
|
interface ApplyRefundRequest {
|
||||||
|
talerRefundUri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForApplyRefundRequest = (): Codec<ApplyRefundRequest> =>
|
||||||
|
makeCodecForObject<ApplyRefundRequest>()
|
||||||
|
.property("talerRefundUri", codecForString)
|
||||||
|
.build("ApplyRefundRequest");
|
||||||
|
|
||||||
|
interface GetWithdrawUriInfoRequest {
|
||||||
|
talerWithdrawUri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForGetWithdrawUriInfoRequest = (): Codec<
|
||||||
|
GetWithdrawUriInfoRequest
|
||||||
|
> =>
|
||||||
|
makeCodecForObject<GetWithdrawUriInfoRequest>()
|
||||||
|
.property("talerWithdrawUri", codecForString)
|
||||||
|
.build("GetWithdrawUriInfoRequest");
|
||||||
|
|
||||||
|
interface AbortProposalRequest {
|
||||||
|
proposalId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForAbortProposalRequest = (): Codec<AbortProposalRequest> =>
|
||||||
|
makeCodecForObject<AbortProposalRequest>()
|
||||||
|
.property("proposalId", codecForString)
|
||||||
|
.build("AbortProposalRequest");
|
||||||
|
|
||||||
|
interface PreparePayRequest {
|
||||||
|
talerPayUri: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForPreparePayRequest = (): Codec<PreparePayRequest> =>
|
||||||
|
makeCodecForObject<PreparePayRequest>()
|
||||||
|
.property("talerPayUri", codecForString)
|
||||||
|
.build("PreparePay");
|
||||||
|
|
||||||
|
interface ConfirmPayRequest {
|
||||||
|
proposalId: string;
|
||||||
|
sessionId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecForConfirmPayRequest = (): Codec<ConfirmPayRequest> =>
|
||||||
|
makeCodecForObject<ConfirmPayRequest>()
|
||||||
|
.property("proposalId", codecForString)
|
||||||
|
.property("sessionId", makeCodecOptional(codecForString))
|
||||||
|
.build("ConfirmPay");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the "wallet-core" API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function dispatchRequestInternal(
|
||||||
|
wallet: Wallet,
|
||||||
|
operation: string,
|
||||||
|
payload: unknown,
|
||||||
|
): Promise<unknown> {
|
||||||
|
switch (operation) {
|
||||||
|
case "withdrawTestkudos":
|
||||||
|
return await withdrawTestBalance(wallet);
|
||||||
|
case "getTransactions": {
|
||||||
|
const req = codecForTransactionsRequest().decode(payload);
|
||||||
|
return await wallet.getTransactions(req);
|
||||||
|
}
|
||||||
|
case "addExchange": {
|
||||||
|
const req = codecForAddExchangeRequest().decode(payload);
|
||||||
|
await wallet.updateExchangeFromUrl(req.exchangeBaseUrl);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case "listExchanges": {
|
||||||
|
return await wallet.getExchanges();
|
||||||
|
}
|
||||||
|
case "getWithdrawUriInfo": {
|
||||||
|
const req = codecForGetWithdrawUriInfoRequest().decode(payload);
|
||||||
|
// FIXME: implement "natively"
|
||||||
|
throw Error("not implemented");
|
||||||
|
}
|
||||||
|
case "acceptManualWithdrawal": {
|
||||||
|
const req = codecForAcceptManualWithdrawalRequet().decode(payload);
|
||||||
|
const res = await wallet.acceptManualWithdrawal(
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
Amounts.parseOrThrow(req.amount),
|
||||||
|
);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
case "getWithdrawalDetailsForAmount": {
|
||||||
|
const req = codecForGetWithdrawalDetailsForAmountRequest().decode(
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
return await wallet.getWithdrawalDetailsForAmount(
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
Amounts.parseOrThrow(req.amount),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "getBalances": {
|
||||||
|
return await wallet.getBalances();
|
||||||
|
}
|
||||||
|
case "getPendingOperations": {
|
||||||
|
return await wallet.getPendingOperations();
|
||||||
|
}
|
||||||
|
case "acceptExchangeTermsOfService": {
|
||||||
|
const req = codecForAcceptExchangeTosRequest().decode(payload);
|
||||||
|
return await wallet.acceptExchangeTermsOfService(
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
req.etag,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "applyRefund": {
|
||||||
|
const req = codecForApplyRefundRequest().decode(payload);
|
||||||
|
return await wallet.applyRefund(req.talerRefundUri);
|
||||||
|
}
|
||||||
|
case "acceptBankIntegratedWithdrawal": {
|
||||||
|
const req = codecForAcceptBankIntegratedWithdrawalRequest().decode(
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
return await wallet.acceptWithdrawal(
|
||||||
|
req.talerWithdrawUri,
|
||||||
|
req.exchangeBaseUrl,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "getExchangeTos": {
|
||||||
|
const req = codecForGetExchangeTosRequest().decode(payload);
|
||||||
|
return wallet.getExchangeTos(req.exchangeBaseUrl);
|
||||||
|
}
|
||||||
|
case "abortProposal": {
|
||||||
|
const req = codecForAbortProposalRequest().decode(payload);
|
||||||
|
return await wallet.refuseProposal(req.proposalId);
|
||||||
|
}
|
||||||
|
case "retryPendingNow": {
|
||||||
|
await wallet.runPending(true);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case "preparePay": {
|
||||||
|
const req = codecForPreparePayRequest().decode(payload);
|
||||||
|
return await wallet.preparePayForUri(req.talerPayUri);
|
||||||
|
}
|
||||||
|
case "confirmPay": {
|
||||||
|
const req = codecForConfirmPayRequest().decode(payload);
|
||||||
|
return await wallet.confirmPay(req.proposalId, req.sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw OperationFailedError.fromCode(
|
||||||
|
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,
|
||||||
|
"unknown operation",
|
||||||
|
{
|
||||||
|
operation,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a request to the wallet-core API.
|
||||||
|
*/
|
||||||
|
export async function handleCoreApiRequest(
|
||||||
|
w: Wallet,
|
||||||
|
operation: string,
|
||||||
|
id: string,
|
||||||
|
payload: unknown,
|
||||||
|
): Promise<unknown> {
|
||||||
|
try {
|
||||||
|
const result = await dispatchRequestInternal(w, operation, payload);
|
||||||
|
const respMsg = {
|
||||||
|
isError: false,
|
||||||
|
operation,
|
||||||
|
id,
|
||||||
|
result,
|
||||||
|
};
|
||||||
|
return respMsg;
|
||||||
|
} catch (e) {
|
||||||
|
if (
|
||||||
|
e instanceof OperationFailedError ||
|
||||||
|
e instanceof OperationFailedAndReportedError
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
operation,
|
||||||
|
id,
|
||||||
|
error: e.operationError,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
isError: true,
|
||||||
|
operation,
|
||||||
|
id,
|
||||||
|
error: makeErrorDetails(
|
||||||
|
TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION,
|
||||||
|
`unexpected exception: ${e}`,
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user