finish refresh correctly, display fees correctly
This commit is contained in:
parent
c2ee8fd9ab
commit
fb6508de9d
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of GNU Taler
|
||||||
(C) 2019 GNUnet e.V.
|
(C) 2019 Taler Systems S.A.
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
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
|
terms of the GNU General Public License as published by the Free Software
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
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
|
You should have received a copy of the GNU General Public License along with
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import os = require("os");
|
import os = require("os");
|
||||||
@ -167,7 +167,10 @@ walletCli
|
|||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
walletCli
|
||||||
.subcommand("", "history", { help: "Show wallet event history." })
|
.subcommand("history", "history", { help: "Show wallet event history." })
|
||||||
|
.flag("json", ["--json"], {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
.maybeOption("from", ["--from"], clk.STRING)
|
.maybeOption("from", ["--from"], clk.STRING)
|
||||||
.maybeOption("to", ["--to"], clk.STRING)
|
.maybeOption("to", ["--to"], clk.STRING)
|
||||||
.maybeOption("limit", ["--limit"], clk.STRING)
|
.maybeOption("limit", ["--limit"], clk.STRING)
|
||||||
@ -175,7 +178,17 @@ walletCli
|
|||||||
.action(async args => {
|
.action(async args => {
|
||||||
await withWallet(args, async wallet => {
|
await withWallet(args, async wallet => {
|
||||||
const history = await wallet.getHistory();
|
const history = await wallet.getHistory();
|
||||||
console.log(JSON.stringify(history, undefined, 2));
|
if (args.history.json) {
|
||||||
|
console.log(JSON.stringify(history, undefined, 2));
|
||||||
|
} else {
|
||||||
|
for (const h of history.history) {
|
||||||
|
console.log(
|
||||||
|
`event at ${new Date(h.timestamp.t_ms).toISOString()} with type ${h.type}:`,
|
||||||
|
);
|
||||||
|
console.log(JSON.stringify(h, undefined, 2));
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -231,7 +244,8 @@ walletCli
|
|||||||
case TalerUriType.TalerWithdraw:
|
case TalerUriType.TalerWithdraw:
|
||||||
{
|
{
|
||||||
const withdrawInfo = await wallet.getWithdrawDetailsForUri(uri);
|
const withdrawInfo = await wallet.getWithdrawDetailsForUri(uri);
|
||||||
const selectedExchange = withdrawInfo.bankWithdrawDetails.suggestedExchange;
|
const selectedExchange =
|
||||||
|
withdrawInfo.bankWithdrawDetails.suggestedExchange;
|
||||||
if (!selectedExchange) {
|
if (!selectedExchange) {
|
||||||
console.error("no suggested exchange!");
|
console.error("no suggested exchange!");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -61,7 +61,6 @@ function getOrderShortInfo(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function collectProposalHistory(
|
async function collectProposalHistory(
|
||||||
tx: TransactionHandle,
|
tx: TransactionHandle,
|
||||||
history: HistoryEvent[],
|
history: HistoryEvent[],
|
||||||
@ -162,6 +161,7 @@ export async function getHistory(
|
|||||||
await ws.db.runWithReadTransaction(
|
await ws.db.runWithReadTransaction(
|
||||||
[
|
[
|
||||||
Stores.currencies,
|
Stores.currencies,
|
||||||
|
Stores.coins,
|
||||||
Stores.exchanges,
|
Stores.exchanges,
|
||||||
Stores.exchangeUpdatedEvents,
|
Stores.exchangeUpdatedEvents,
|
||||||
Stores.proposals,
|
Stores.proposals,
|
||||||
@ -220,15 +220,22 @@ export async function getHistory(
|
|||||||
|
|
||||||
await collectProposalHistory(tx, history, historyQuery);
|
await collectProposalHistory(tx, history, historyQuery);
|
||||||
|
|
||||||
await tx.iter(Stores.payEvents).forEachAsync(async (pe) => {
|
await tx.iter(Stores.payEvents).forEachAsync(async pe => {
|
||||||
const proposal = await tx.get(Stores.proposals, pe.proposalId);
|
const proposal = await tx.get(Stores.proposals, pe.proposalId);
|
||||||
if (!proposal) {
|
if (!proposal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const purchase = await tx.get(Stores.purchases, pe.proposalId);
|
||||||
|
if (!purchase) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const orderShortInfo = getOrderShortInfo(proposal);
|
const orderShortInfo = getOrderShortInfo(proposal);
|
||||||
if (!orderShortInfo) {
|
if (!orderShortInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const amountPaidWithFees = Amounts.sum(
|
||||||
|
purchase.payReq.coins.map(x => Amounts.parseOrThrow(x.contribution)),
|
||||||
|
).amount;
|
||||||
history.push({
|
history.push({
|
||||||
type: HistoryEventType.PaymentSent,
|
type: HistoryEventType.PaymentSent,
|
||||||
eventId: makeEventId(HistoryEventType.PaymentSent, pe.proposalId),
|
eventId: makeEventId(HistoryEventType.PaymentSent, pe.proposalId),
|
||||||
@ -236,10 +243,12 @@ export async function getHistory(
|
|||||||
replay: pe.isReplay,
|
replay: pe.isReplay,
|
||||||
sessionId: pe.sessionId,
|
sessionId: pe.sessionId,
|
||||||
timestamp: pe.timestamp,
|
timestamp: pe.timestamp,
|
||||||
|
numCoins: purchase.payReq.coins.length,
|
||||||
|
amountPaidWithFees: Amounts.toString(amountPaidWithFees),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await tx.iter(Stores.refreshGroups).forEachAsync(async (rg) => {
|
await tx.iter(Stores.refreshGroups).forEachAsync(async rg => {
|
||||||
if (!rg.timestampFinished) {
|
if (!rg.timestampFinished) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -251,23 +260,26 @@ export async function getHistory(
|
|||||||
for (let i = 0; i < rg.refreshSessionPerCoin.length; i++) {
|
for (let i = 0; i < rg.refreshSessionPerCoin.length; i++) {
|
||||||
const session = rg.refreshSessionPerCoin[i];
|
const session = rg.refreshSessionPerCoin[i];
|
||||||
numInputCoins++;
|
numInputCoins++;
|
||||||
|
const c = await tx.get(Stores.coins, rg.oldCoinPubs[i]);
|
||||||
|
if (!c) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (session) {
|
if (session) {
|
||||||
numRefreshedInputCoins++;
|
numRefreshedInputCoins++;
|
||||||
amountsRaw.push(session.amountRefreshInput);
|
amountsRaw.push(session.amountRefreshInput);
|
||||||
|
amountsRaw.push(c.currentAmount);
|
||||||
amountsEffective.push(session.amountRefreshOutput);
|
amountsEffective.push(session.amountRefreshOutput);
|
||||||
numOutputCoins += session.newDenoms.length;
|
numOutputCoins += session.newDenoms.length;
|
||||||
} else {
|
} else {
|
||||||
const c = await tx.get(Stores.coins, rg.oldCoinPubs[i]);
|
|
||||||
if (!c) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
amountsRaw.push(c.currentAmount);
|
amountsRaw.push(c.currentAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let amountRefreshedRaw = Amounts.sum(amountsRaw).amount;
|
let amountRefreshedRaw = Amounts.sum(amountsRaw).amount;
|
||||||
let amountRefreshedEffective: AmountJson;
|
let amountRefreshedEffective: AmountJson;
|
||||||
if (amountsEffective.length == 0) {
|
if (amountsEffective.length == 0) {
|
||||||
amountRefreshedEffective = Amounts.getZero(amountRefreshedRaw.currency);
|
amountRefreshedEffective = Amounts.getZero(
|
||||||
|
amountRefreshedRaw.currency,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
amountRefreshedEffective = Amounts.sum(amountsEffective).amount;
|
amountRefreshedEffective = Amounts.sum(amountsEffective).amount;
|
||||||
}
|
}
|
||||||
@ -285,7 +297,7 @@ export async function getHistory(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async (ru) => {
|
tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async ru => {
|
||||||
const reserve = await tx.get(Stores.reserves, ru.reservePub);
|
const reserve = await tx.get(Stores.reserves, ru.reservePub);
|
||||||
if (!reserve) {
|
if (!reserve) {
|
||||||
return;
|
return;
|
||||||
@ -295,28 +307,31 @@ export async function getHistory(
|
|||||||
reserveCreationDetail = {
|
reserveCreationDetail = {
|
||||||
type: ReserveType.TalerBankWithdraw,
|
type: ReserveType.TalerBankWithdraw,
|
||||||
bankUrl: reserve.bankWithdrawStatusUrl,
|
bankUrl: reserve.bankWithdrawStatusUrl,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
reserveCreationDetail = {
|
reserveCreationDetail = {
|
||||||
type: ReserveType.Manual,
|
type: ReserveType.Manual,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
history.push({
|
history.push({
|
||||||
type: HistoryEventType.ReserveBalanceUpdated,
|
type: HistoryEventType.ReserveBalanceUpdated,
|
||||||
eventId: makeEventId(HistoryEventType.ReserveBalanceUpdated, ru.reserveUpdateId),
|
eventId: makeEventId(
|
||||||
|
HistoryEventType.ReserveBalanceUpdated,
|
||||||
|
ru.reserveUpdateId,
|
||||||
|
),
|
||||||
amountExpected: ru.amountExpected,
|
amountExpected: ru.amountExpected,
|
||||||
amountReserveBalance: ru.amountReserveBalance,
|
amountReserveBalance: ru.amountReserveBalance,
|
||||||
timestamp: reserve.timestampCreated,
|
timestamp: ru.timestamp,
|
||||||
newHistoryTransactions: ru.newHistoryTransactions,
|
newHistoryTransactions: ru.newHistoryTransactions,
|
||||||
reserveShortInfo: {
|
reserveShortInfo: {
|
||||||
exchangeBaseUrl: reserve.exchangeBaseUrl,
|
exchangeBaseUrl: reserve.exchangeBaseUrl,
|
||||||
reserveCreationDetail,
|
reserveCreationDetail,
|
||||||
reservePub: reserve.reservePub,
|
reservePub: reserve.reservePub,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.iter(Stores.tips).forEach((tip) => {
|
tx.iter(Stores.tips).forEach(tip => {
|
||||||
if (tip.acceptedTimestamp) {
|
if (tip.acceptedTimestamp) {
|
||||||
history.push({
|
history.push({
|
||||||
type: HistoryEventType.TipAccepted,
|
type: HistoryEventType.TipAccepted,
|
||||||
@ -328,7 +343,7 @@ export async function getHistory(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tx.iter(Stores.refundEvents).forEachAsync(async (re) => {
|
tx.iter(Stores.refundEvents).forEachAsync(async re => {
|
||||||
const proposal = await tx.get(Stores.proposals, re.proposalId);
|
const proposal = await tx.get(Stores.proposals, re.proposalId);
|
||||||
if (!proposal) {
|
if (!proposal) {
|
||||||
return;
|
return;
|
||||||
@ -341,7 +356,9 @@ export async function getHistory(
|
|||||||
if (!orderShortInfo) {
|
if (!orderShortInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const purchaseAmount = Amounts.parseOrThrow(purchase.contractTerms.amount);
|
const purchaseAmount = Amounts.parseOrThrow(
|
||||||
|
purchase.contractTerms.amount,
|
||||||
|
);
|
||||||
let amountRefundedRaw = Amounts.getZero(purchaseAmount.currency);
|
let amountRefundedRaw = Amounts.getZero(purchaseAmount.currency);
|
||||||
let amountRefundedInvalid = Amounts.getZero(purchaseAmount.currency);
|
let amountRefundedInvalid = Amounts.getZero(purchaseAmount.currency);
|
||||||
let amountRefundedEffective = Amounts.getZero(purchaseAmount.currency);
|
let amountRefundedEffective = Amounts.getZero(purchaseAmount.currency);
|
||||||
@ -352,9 +369,16 @@ export async function getHistory(
|
|||||||
}
|
}
|
||||||
const refundAmount = Amounts.parseOrThrow(r.perm.refund_amount);
|
const refundAmount = Amounts.parseOrThrow(r.perm.refund_amount);
|
||||||
const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
|
const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
|
||||||
amountRefundedRaw = Amounts.add(amountRefundedRaw, refundAmount).amount;
|
amountRefundedRaw = Amounts.add(amountRefundedRaw, refundAmount)
|
||||||
amountRefundedEffective = Amounts.add(amountRefundedEffective, refundAmount).amount;
|
.amount;
|
||||||
amountRefundedEffective = Amounts.sub(amountRefundedEffective, refundFee).amount;
|
amountRefundedEffective = Amounts.add(
|
||||||
|
amountRefundedEffective,
|
||||||
|
refundAmount,
|
||||||
|
).amount;
|
||||||
|
amountRefundedEffective = Amounts.sub(
|
||||||
|
amountRefundedEffective,
|
||||||
|
refundFee,
|
||||||
|
).amount;
|
||||||
});
|
});
|
||||||
Object.keys(purchase.refundState.refundsFailed).forEach((x, i) => {
|
Object.keys(purchase.refundState.refundsFailed).forEach((x, i) => {
|
||||||
const r = purchase.refundState.refundsFailed[x];
|
const r = purchase.refundState.refundsFailed[x];
|
||||||
@ -365,7 +389,10 @@ export async function getHistory(
|
|||||||
const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
|
const refundFee = Amounts.parseOrThrow(r.perm.refund_fee);
|
||||||
amountRefundedRaw = Amounts.add(amountRefundedRaw, ra).amount;
|
amountRefundedRaw = Amounts.add(amountRefundedRaw, ra).amount;
|
||||||
amountRefundedInvalid = Amounts.add(amountRefundedInvalid, ra).amount;
|
amountRefundedInvalid = Amounts.add(amountRefundedInvalid, ra).amount;
|
||||||
amountRefundedEffective = Amounts.sub(amountRefundedEffective, refundFee).amount;
|
amountRefundedEffective = Amounts.sub(
|
||||||
|
amountRefundedEffective,
|
||||||
|
refundFee,
|
||||||
|
).amount;
|
||||||
});
|
});
|
||||||
history.push({
|
history.push({
|
||||||
type: HistoryEventType.Refund,
|
type: HistoryEventType.Refund,
|
||||||
|
@ -224,6 +224,8 @@ async function gatherRefreshPending(
|
|||||||
type: PendingOperationType.Refresh,
|
type: PendingOperationType.Refresh,
|
||||||
givesLifeness: true,
|
givesLifeness: true,
|
||||||
refreshGroupId: r.refreshGroupId,
|
refreshGroupId: r.refreshGroupId,
|
||||||
|
finishedPerCoin: r.finishedPerCoin,
|
||||||
|
retryInfo: r.retryInfo,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -144,10 +144,22 @@ async function refreshCreateSession(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rg.finishedPerCoin[coinIndex] = true;
|
rg.finishedPerCoin[coinIndex] = true;
|
||||||
|
rg.finishedPerCoin[coinIndex] = true;
|
||||||
|
let allDone = true;
|
||||||
|
for (const f of rg.finishedPerCoin) {
|
||||||
|
if (!f) {
|
||||||
|
allDone = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allDone) {
|
||||||
|
rg.timestampFinished = getTimestampNow();
|
||||||
|
rg.retryInfo = initRetryInfo(false);
|
||||||
|
}
|
||||||
await tx.put(Stores.refreshGroups, rg);
|
await tx.put(Stores.refreshGroups, rg);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
ws.notify({ type: NotificationType.RefreshRefused });
|
ws.notify({ type: NotificationType.RefreshUnwarranted });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,12 +34,14 @@ import {
|
|||||||
updateRetryInfoTimeout,
|
updateRetryInfoTimeout,
|
||||||
ReserveUpdatedEventRecord,
|
ReserveUpdatedEventRecord,
|
||||||
} from "../types/dbTypes";
|
} from "../types/dbTypes";
|
||||||
import {
|
import { TransactionAbort } from "../util/query";
|
||||||
TransactionAbort,
|
|
||||||
} from "../util/query";
|
|
||||||
import { Logger } from "../util/logging";
|
import { Logger } from "../util/logging";
|
||||||
import * as Amounts from "../util/amounts";
|
import * as Amounts from "../util/amounts";
|
||||||
import { updateExchangeFromUrl, getExchangeTrust, getExchangePaytoUri } from "./exchanges";
|
import {
|
||||||
|
updateExchangeFromUrl,
|
||||||
|
getExchangeTrust,
|
||||||
|
getExchangePaytoUri,
|
||||||
|
} from "./exchanges";
|
||||||
import { WithdrawOperationStatusResponse } from "../types/talerTypes";
|
import { WithdrawOperationStatusResponse } from "../types/talerTypes";
|
||||||
import { assertUnreachable } from "../util/assertUnreachable";
|
import { assertUnreachable } from "../util/assertUnreachable";
|
||||||
import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
|
import { encodeCrock, getRandomBytes } from "../crypto/talerCrypto";
|
||||||
@ -49,7 +51,10 @@ import {
|
|||||||
processWithdrawSession,
|
processWithdrawSession,
|
||||||
getBankWithdrawalInfo,
|
getBankWithdrawalInfo,
|
||||||
} from "./withdraw";
|
} from "./withdraw";
|
||||||
import { guardOperationException, OperationFailedAndReportedError } from "./errors";
|
import {
|
||||||
|
guardOperationException,
|
||||||
|
OperationFailedAndReportedError,
|
||||||
|
} from "./errors";
|
||||||
import { NotificationType } from "../types/notifications";
|
import { NotificationType } from "../types/notifications";
|
||||||
import { codecForReserveStatus } from "../types/ReserveStatus";
|
import { codecForReserveStatus } from "../types/ReserveStatus";
|
||||||
|
|
||||||
@ -206,7 +211,6 @@ export async function processReserve(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function registerReserveWithBank(
|
async function registerReserveWithBank(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
reservePub: string,
|
reservePub: string,
|
||||||
@ -231,7 +235,6 @@ async function registerReserveWithBank(
|
|||||||
reserve_pub: reservePub,
|
reserve_pub: reservePub,
|
||||||
selected_exchange: reserve.exchangeWire,
|
selected_exchange: reserve.exchangeWire,
|
||||||
});
|
});
|
||||||
console.log("got response", bankResp);
|
|
||||||
await ws.db.mutate(Stores.reserves, reservePub, r => {
|
await ws.db.mutate(Stores.reserves, reservePub, r => {
|
||||||
switch (r.reserveStatus) {
|
switch (r.reserveStatus) {
|
||||||
case ReserveRecordStatus.REGISTERING_BANK:
|
case ReserveRecordStatus.REGISTERING_BANK:
|
||||||
@ -245,7 +248,7 @@ async function registerReserveWithBank(
|
|||||||
r.retryInfo = initRetryInfo();
|
r.retryInfo = initRetryInfo();
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
ws.notify( { type: NotificationType.Wildcard });
|
ws.notify({ type: NotificationType.Wildcard });
|
||||||
return processReserveBankStatus(ws, reservePub);
|
return processReserveBankStatus(ws, reservePub);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,14 +285,16 @@ async function processReserveBankStatusImpl(
|
|||||||
try {
|
try {
|
||||||
const statusResp = await ws.http.get(bankStatusUrl);
|
const statusResp = await ws.http.get(bankStatusUrl);
|
||||||
if (statusResp.status !== 200) {
|
if (statusResp.status !== 200) {
|
||||||
throw Error(`unexpected status ${statusResp.status} for bank status query`);
|
throw Error(
|
||||||
|
`unexpected status ${statusResp.status} for bank status query`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
status = WithdrawOperationStatusResponse.checked(await statusResp.json());
|
status = WithdrawOperationStatusResponse.checked(await statusResp.json());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.notify( { type: NotificationType.Wildcard });
|
ws.notify({ type: NotificationType.Wildcard });
|
||||||
|
|
||||||
if (status.selection_done) {
|
if (status.selection_done) {
|
||||||
if (reserve.reserveStatus === ReserveRecordStatus.REGISTERING_BANK) {
|
if (reserve.reserveStatus === ReserveRecordStatus.REGISTERING_BANK) {
|
||||||
@ -330,7 +335,7 @@ async function processReserveBankStatusImpl(
|
|||||||
});
|
});
|
||||||
await incrementReserveRetry(ws, reservePub, undefined);
|
await incrementReserveRetry(ws, reservePub, undefined);
|
||||||
}
|
}
|
||||||
ws.notify( { type: NotificationType.Wildcard });
|
ws.notify({ type: NotificationType.Wildcard });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function incrementReserveRetry(
|
async function incrementReserveRetry(
|
||||||
@ -351,7 +356,12 @@ async function incrementReserveRetry(
|
|||||||
r.lastError = err;
|
r.lastError = err;
|
||||||
await tx.put(Stores.reserves, r);
|
await tx.put(Stores.reserves, r);
|
||||||
});
|
});
|
||||||
ws.notify({ type: NotificationType.ReserveOperationError });
|
if (err) {
|
||||||
|
ws.notify({
|
||||||
|
type: NotificationType.ReserveOperationError,
|
||||||
|
operationError: err,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,7 +396,7 @@ async function updateReserve(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (resp.status !== 200) {
|
if (resp.status !== 200) {
|
||||||
throw Error(`unexpected status code ${resp.status} for reserve/status`)
|
throw Error(`unexpected status code ${resp.status} for reserve/status`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const m = e.message;
|
const m = e.message;
|
||||||
@ -400,68 +410,73 @@ async function updateReserve(
|
|||||||
const respJson = await resp.json();
|
const respJson = await resp.json();
|
||||||
const reserveInfo = codecForReserveStatus.decode(respJson);
|
const reserveInfo = codecForReserveStatus.decode(respJson);
|
||||||
const balance = Amounts.parseOrThrow(reserveInfo.balance);
|
const balance = Amounts.parseOrThrow(reserveInfo.balance);
|
||||||
await ws.db.runWithWriteTransaction([Stores.reserves, Stores.reserveUpdatedEvents], async (tx) => {
|
await ws.db.runWithWriteTransaction(
|
||||||
const r = await tx.get(Stores.reserves, reservePub);
|
[Stores.reserves, Stores.reserveUpdatedEvents],
|
||||||
if (!r) {
|
async tx => {
|
||||||
return;
|
const r = await tx.get(Stores.reserves, reservePub);
|
||||||
}
|
if (!r) {
|
||||||
if (r.reserveStatus !== ReserveRecordStatus.QUERYING_STATUS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newHistoryTransactions = reserveInfo.history.slice(r.reserveTransactions.length);
|
|
||||||
|
|
||||||
const reserveUpdateId = encodeCrock(getRandomBytes(32));
|
|
||||||
|
|
||||||
// FIXME: check / compare history!
|
|
||||||
if (!r.lastSuccessfulStatusQuery) {
|
|
||||||
// FIXME: check if this matches initial expectations
|
|
||||||
r.amountWithdrawRemaining = balance;
|
|
||||||
const reserveUpdate: ReserveUpdatedEventRecord = {
|
|
||||||
reservePub: r.reservePub,
|
|
||||||
timestamp: getTimestampNow(),
|
|
||||||
amountReserveBalance: Amounts.toString(balance),
|
|
||||||
amountExpected: Amounts.toString(reserve.amountInitiallyRequested),
|
|
||||||
newHistoryTransactions,
|
|
||||||
reserveUpdateId,
|
|
||||||
};
|
|
||||||
await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
|
|
||||||
} else {
|
|
||||||
const expectedBalance = Amounts.sub(
|
|
||||||
r.amountWithdrawAllocated,
|
|
||||||
r.amountWithdrawCompleted,
|
|
||||||
);
|
|
||||||
const cmp = Amounts.cmp(balance, expectedBalance.amount);
|
|
||||||
if (cmp == 0) {
|
|
||||||
// Nothing changed.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cmp > 0) {
|
if (r.reserveStatus !== ReserveRecordStatus.QUERYING_STATUS) {
|
||||||
const extra = Amounts.sub(balance, expectedBalance.amount).amount;
|
return;
|
||||||
r.amountWithdrawRemaining = Amounts.add(
|
|
||||||
r.amountWithdrawRemaining,
|
|
||||||
extra,
|
|
||||||
).amount;
|
|
||||||
} else {
|
|
||||||
// We're missing some money.
|
|
||||||
}
|
}
|
||||||
const reserveUpdate: ReserveUpdatedEventRecord = {
|
|
||||||
reservePub: r.reservePub,
|
const newHistoryTransactions = reserveInfo.history.slice(
|
||||||
timestamp: getTimestampNow(),
|
r.reserveTransactions.length,
|
||||||
amountReserveBalance: Amounts.toString(balance),
|
);
|
||||||
amountExpected: Amounts.toString(expectedBalance.amount),
|
|
||||||
newHistoryTransactions,
|
const reserveUpdateId = encodeCrock(getRandomBytes(32));
|
||||||
reserveUpdateId,
|
|
||||||
};
|
// FIXME: check / compare history!
|
||||||
await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
|
if (!r.lastSuccessfulStatusQuery) {
|
||||||
}
|
// FIXME: check if this matches initial expectations
|
||||||
r.lastSuccessfulStatusQuery = getTimestampNow();
|
r.amountWithdrawRemaining = balance;
|
||||||
r.reserveStatus = ReserveRecordStatus.WITHDRAWING;
|
const reserveUpdate: ReserveUpdatedEventRecord = {
|
||||||
r.retryInfo = initRetryInfo();
|
reservePub: r.reservePub,
|
||||||
r.reserveTransactions = reserveInfo.history;
|
timestamp: getTimestampNow(),
|
||||||
await tx.put(Stores.reserves, r);
|
amountReserveBalance: Amounts.toString(balance),
|
||||||
});
|
amountExpected: Amounts.toString(reserve.amountInitiallyRequested),
|
||||||
ws.notify( { type: NotificationType.ReserveUpdated });
|
newHistoryTransactions,
|
||||||
|
reserveUpdateId,
|
||||||
|
};
|
||||||
|
await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
|
||||||
|
} else {
|
||||||
|
const expectedBalance = Amounts.sub(
|
||||||
|
r.amountWithdrawAllocated,
|
||||||
|
r.amountWithdrawCompleted,
|
||||||
|
);
|
||||||
|
const cmp = Amounts.cmp(balance, expectedBalance.amount);
|
||||||
|
if (cmp == 0) {
|
||||||
|
// Nothing changed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cmp > 0) {
|
||||||
|
const extra = Amounts.sub(balance, expectedBalance.amount).amount;
|
||||||
|
r.amountWithdrawRemaining = Amounts.add(
|
||||||
|
r.amountWithdrawRemaining,
|
||||||
|
extra,
|
||||||
|
).amount;
|
||||||
|
} else {
|
||||||
|
// We're missing some money.
|
||||||
|
}
|
||||||
|
const reserveUpdate: ReserveUpdatedEventRecord = {
|
||||||
|
reservePub: r.reservePub,
|
||||||
|
timestamp: getTimestampNow(),
|
||||||
|
amountReserveBalance: Amounts.toString(balance),
|
||||||
|
amountExpected: Amounts.toString(expectedBalance.amount),
|
||||||
|
newHistoryTransactions,
|
||||||
|
reserveUpdateId,
|
||||||
|
};
|
||||||
|
await tx.put(Stores.reserveUpdatedEvents, reserveUpdate);
|
||||||
|
}
|
||||||
|
r.lastSuccessfulStatusQuery = getTimestampNow();
|
||||||
|
r.reserveStatus = ReserveRecordStatus.WITHDRAWING;
|
||||||
|
r.retryInfo = initRetryInfo();
|
||||||
|
r.reserveTransactions = reserveInfo.history;
|
||||||
|
await tx.put(Stores.reserves, r);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ws.notify({ type: NotificationType.ReserveUpdated });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processReserveImpl(
|
async function processReserveImpl(
|
||||||
@ -655,8 +670,6 @@ async function depleteReserve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function createTalerWithdrawReserve(
|
export async function createTalerWithdrawReserve(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
talerWithdrawUri: string,
|
talerWithdrawUri: string,
|
||||||
@ -683,4 +696,4 @@ export async function createTalerWithdrawReserve(
|
|||||||
reservePub: reserve.reservePub,
|
reservePub: reserve.reservePub,
|
||||||
confirmTransferUrl: withdrawInfo.confirmTransferUrl,
|
confirmTransferUrl: withdrawInfo.confirmTransferUrl,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -485,6 +485,16 @@ export interface HistoryPaymentSent {
|
|||||||
*/
|
*/
|
||||||
replay: boolean;
|
replay: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of coins that were involved in the payment.
|
||||||
|
*/
|
||||||
|
numCoins: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount that was paid, including deposit and wire fees.
|
||||||
|
*/
|
||||||
|
amountPaidWithFees: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session ID that the payment was (re-)submitted under.
|
* Session ID that the payment was (re-)submitted under.
|
||||||
*/
|
*/
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { OperationError } from "./walletTypes";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This file is part of GNU Taler
|
This file is part of GNU Taler
|
||||||
(C) 2019 GNUnet e.V.
|
(C) 2019 GNUnet e.V.
|
||||||
@ -29,7 +31,7 @@ export const enum NotificationType {
|
|||||||
RefreshRevealed = "refresh-revealed",
|
RefreshRevealed = "refresh-revealed",
|
||||||
RefreshMelted = "refresh-melted",
|
RefreshMelted = "refresh-melted",
|
||||||
RefreshStarted = "refresh-started",
|
RefreshStarted = "refresh-started",
|
||||||
RefreshRefused = "refresh-refused",
|
RefreshUnwarranted = "refresh-unwarranted",
|
||||||
ReserveUpdated = "reserve-updated",
|
ReserveUpdated = "reserve-updated",
|
||||||
ReserveConfirmed = "reserve-confirmed",
|
ReserveConfirmed = "reserve-confirmed",
|
||||||
ReserveDepleted = "reserve-depleted",
|
ReserveDepleted = "reserve-depleted",
|
||||||
@ -100,7 +102,7 @@ export interface RefreshStartedNotification {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RefreshRefusedNotification {
|
export interface RefreshRefusedNotification {
|
||||||
type: NotificationType.RefreshRefused;
|
type: NotificationType.RefreshUnwarranted;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveUpdatedNotification {
|
export interface ReserveUpdatedNotification {
|
||||||
@ -170,6 +172,7 @@ export interface WithdrawOperationErrorNotification {
|
|||||||
|
|
||||||
export interface ReserveOperationErrorNotification {
|
export interface ReserveOperationErrorNotification {
|
||||||
type: NotificationType.ReserveOperationError;
|
type: NotificationType.ReserveOperationError;
|
||||||
|
operationError: OperationError;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReserveCreatedNotification {
|
export interface ReserveCreatedNotification {
|
||||||
|
@ -87,6 +87,8 @@ export interface PendingRefreshOperation {
|
|||||||
type: PendingOperationType.Refresh;
|
type: PendingOperationType.Refresh;
|
||||||
lastError?: OperationError;
|
lastError?: OperationError;
|
||||||
refreshGroupId: string;
|
refreshGroupId: string;
|
||||||
|
finishedPerCoin: boolean[];
|
||||||
|
retryInfo: RetryInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PendingProposalDownloadOperation {
|
export interface PendingProposalDownloadOperation {
|
||||||
|
Loading…
Reference in New Issue
Block a user