new transactions API: withdrawal
This commit is contained in:
parent
857a2b9dca
commit
6206b418ff
@ -231,6 +231,15 @@ walletCli
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
walletCli
|
||||||
|
.subcommand("", "transactions", { help: "Show transactions." })
|
||||||
|
.action(async (args) => {
|
||||||
|
await withWallet(args, async (wallet) => {
|
||||||
|
const pending = await wallet.getTransactions({});
|
||||||
|
console.log(JSON.stringify(pending, undefined, 2));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
async function asyncSleep(milliSeconds: number): Promise<void> {
|
async function asyncSleep(milliSeconds: number): Promise<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
setTimeout(() => resolve(), milliSeconds);
|
setTimeout(() => resolve(), milliSeconds);
|
||||||
|
@ -375,10 +375,10 @@ export async function getHistory(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let reserveCreationDetail: ReserveCreationDetail;
|
let reserveCreationDetail: ReserveCreationDetail;
|
||||||
if (reserve.bankWithdrawStatusUrl) {
|
if (reserve.bankInfo) {
|
||||||
reserveCreationDetail = {
|
reserveCreationDetail = {
|
||||||
type: ReserveType.TalerBankWithdraw,
|
type: ReserveType.TalerBankWithdraw,
|
||||||
bankUrl: reserve.bankWithdrawStatusUrl,
|
bankUrl: reserve.bankInfo.statusUrl,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
reserveCreationDetail = {
|
reserveCreationDetail = {
|
||||||
|
@ -150,7 +150,7 @@ async function gatherReservePending(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// FIXME: this should be optimized by using an index for "onlyDue==true".
|
// FIXME: this should be optimized by using an index for "onlyDue==true".
|
||||||
await tx.iter(Stores.reserves).forEach((reserve) => {
|
await tx.iter(Stores.reserves).forEach((reserve) => {
|
||||||
const reserveType = reserve.bankWithdrawStatusUrl
|
const reserveType = reserve.bankInfo
|
||||||
? ReserveType.TalerBankWithdraw
|
? ReserveType.TalerBankWithdraw
|
||||||
: ReserveType.Manual;
|
: ReserveType.Manual;
|
||||||
if (!reserve.retryInfo.active) {
|
if (!reserve.retryInfo.active) {
|
||||||
|
@ -108,7 +108,14 @@ export async function createReserve(
|
|||||||
senderWire: req.senderWire,
|
senderWire: req.senderWire,
|
||||||
timestampConfirmed: undefined,
|
timestampConfirmed: undefined,
|
||||||
timestampReserveInfoPosted: undefined,
|
timestampReserveInfoPosted: undefined,
|
||||||
bankWithdrawStatusUrl: req.bankWithdrawStatusUrl,
|
bankInfo: req.bankWithdrawStatusUrl
|
||||||
|
? {
|
||||||
|
statusUrl: req.bankWithdrawStatusUrl,
|
||||||
|
amount: req.amount,
|
||||||
|
bankWithdrawalGroupId: encodeCrock(getRandomBytes(32)),
|
||||||
|
withdrawalStarted: false,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
exchangeWire: req.exchangeWire,
|
exchangeWire: req.exchangeWire,
|
||||||
reserveStatus,
|
reserveStatus,
|
||||||
lastSuccessfulStatusQuery: undefined,
|
lastSuccessfulStatusQuery: undefined,
|
||||||
@ -173,10 +180,10 @@ export async function createReserve(
|
|||||||
],
|
],
|
||||||
async (tx) => {
|
async (tx) => {
|
||||||
// Check if we have already created a reserve for that bankWithdrawStatusUrl
|
// Check if we have already created a reserve for that bankWithdrawStatusUrl
|
||||||
if (reserveRecord.bankWithdrawStatusUrl) {
|
if (reserveRecord.bankInfo?.statusUrl) {
|
||||||
const bwi = await tx.get(
|
const bwi = await tx.get(
|
||||||
Stores.bankWithdrawUris,
|
Stores.bankWithdrawUris,
|
||||||
reserveRecord.bankWithdrawStatusUrl,
|
reserveRecord.bankInfo.statusUrl,
|
||||||
);
|
);
|
||||||
if (bwi) {
|
if (bwi) {
|
||||||
const otherReserve = await tx.get(Stores.reserves, bwi.reservePub);
|
const otherReserve = await tx.get(Stores.reserves, bwi.reservePub);
|
||||||
@ -192,7 +199,7 @@ export async function createReserve(
|
|||||||
}
|
}
|
||||||
await tx.put(Stores.bankWithdrawUris, {
|
await tx.put(Stores.bankWithdrawUris, {
|
||||||
reservePub: reserveRecord.reservePub,
|
reservePub: reserveRecord.reservePub,
|
||||||
talerWithdrawUri: reserveRecord.bankWithdrawStatusUrl,
|
talerWithdrawUri: reserveRecord.bankInfo.statusUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await tx.put(Stores.currencies, cr);
|
await tx.put(Stores.currencies, cr);
|
||||||
@ -279,7 +286,7 @@ async function registerReserveWithBank(
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bankStatusUrl = reserve.bankWithdrawStatusUrl;
|
const bankStatusUrl = reserve.bankInfo?.statusUrl;
|
||||||
if (!bankStatusUrl) {
|
if (!bankStatusUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -333,7 +340,7 @@ async function processReserveBankStatusImpl(
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const bankStatusUrl = reserve.bankWithdrawStatusUrl;
|
const bankStatusUrl = reserve.bankInfo?.statusUrl;
|
||||||
if (!bankStatusUrl) {
|
if (!bankStatusUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -382,7 +389,9 @@ async function processReserveBankStatusImpl(
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r.bankWithdrawConfirmUrl = status.confirm_transfer_url;
|
if (r.bankInfo) {
|
||||||
|
r.bankInfo.confirmUrl = status.confirm_transfer_url;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
});
|
});
|
||||||
await incrementReserveRetry(ws, reservePub, undefined);
|
await incrementReserveRetry(ws, reservePub, undefined);
|
||||||
@ -673,35 +682,7 @@ async function depleteReserve(
|
|||||||
|
|
||||||
logger.trace("selected denominations");
|
logger.trace("selected denominations");
|
||||||
|
|
||||||
const withdrawalGroupId = encodeCrock(randomBytes(32));
|
const newWithdrawalGroup = await ws.db.runWithWriteTransaction(
|
||||||
|
|
||||||
logger.trace("created plachets");
|
|
||||||
|
|
||||||
const withdrawalRecord: WithdrawalGroupRecord = {
|
|
||||||
withdrawalGroupId: withdrawalGroupId,
|
|
||||||
exchangeBaseUrl: reserve.exchangeBaseUrl,
|
|
||||||
source: {
|
|
||||||
type: WithdrawalSourceType.Reserve,
|
|
||||||
reservePub: reserve.reservePub,
|
|
||||||
},
|
|
||||||
rawWithdrawalAmount: withdrawAmount,
|
|
||||||
timestampStart: getTimestampNow(),
|
|
||||||
retryInfo: initRetryInfo(),
|
|
||||||
lastErrorPerCoin: {},
|
|
||||||
lastError: undefined,
|
|
||||||
denomsSel: {
|
|
||||||
totalCoinValue: denomsForWithdraw.totalCoinValue,
|
|
||||||
totalWithdrawCost: denomsForWithdraw.totalWithdrawCost,
|
|
||||||
selectedDenoms: denomsForWithdraw.selectedDenoms.map((x) => {
|
|
||||||
return {
|
|
||||||
count: x.count,
|
|
||||||
denomPubHash: x.denom.denomPubHash,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const success = await ws.db.runWithWriteTransaction(
|
|
||||||
[
|
[
|
||||||
Stores.withdrawalGroups,
|
Stores.withdrawalGroups,
|
||||||
Stores.reserves,
|
Stores.reserves,
|
||||||
@ -748,20 +729,55 @@ async function depleteReserve(
|
|||||||
}
|
}
|
||||||
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
|
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
|
||||||
newReserve.retryInfo = initRetryInfo(false);
|
newReserve.retryInfo = initRetryInfo(false);
|
||||||
|
|
||||||
|
let withdrawalGroupId: string;
|
||||||
|
|
||||||
|
const bankInfo = newReserve.bankInfo;
|
||||||
|
if (bankInfo && !bankInfo.withdrawalStarted) {
|
||||||
|
withdrawalGroupId = bankInfo.bankWithdrawalGroupId;
|
||||||
|
bankInfo.withdrawalStarted = true;
|
||||||
|
} else {
|
||||||
|
withdrawalGroupId = encodeCrock(randomBytes(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
const withdrawalRecord: WithdrawalGroupRecord = {
|
||||||
|
withdrawalGroupId: withdrawalGroupId,
|
||||||
|
exchangeBaseUrl: newReserve.exchangeBaseUrl,
|
||||||
|
source: {
|
||||||
|
type: WithdrawalSourceType.Reserve,
|
||||||
|
reservePub: newReserve.reservePub,
|
||||||
|
},
|
||||||
|
rawWithdrawalAmount: withdrawAmount,
|
||||||
|
timestampStart: getTimestampNow(),
|
||||||
|
retryInfo: initRetryInfo(),
|
||||||
|
lastErrorPerCoin: {},
|
||||||
|
lastError: undefined,
|
||||||
|
denomsSel: {
|
||||||
|
totalCoinValue: denomsForWithdraw.totalCoinValue,
|
||||||
|
totalWithdrawCost: denomsForWithdraw.totalWithdrawCost,
|
||||||
|
selectedDenoms: denomsForWithdraw.selectedDenoms.map((x) => {
|
||||||
|
return {
|
||||||
|
count: x.count,
|
||||||
|
denomPubHash: x.denom.denomPubHash,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
await tx.put(Stores.reserves, newReserve);
|
await tx.put(Stores.reserves, newReserve);
|
||||||
await tx.put(Stores.reserveHistory, newHist);
|
await tx.put(Stores.reserveHistory, newHist);
|
||||||
await tx.put(Stores.withdrawalGroups, withdrawalRecord);
|
await tx.put(Stores.withdrawalGroups, withdrawalRecord);
|
||||||
return true;
|
return withdrawalRecord;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (newWithdrawalGroup) {
|
||||||
console.log("processing new withdraw group");
|
console.log("processing new withdraw group");
|
||||||
ws.notify({
|
ws.notify({
|
||||||
type: NotificationType.WithdrawGroupCreated,
|
type: NotificationType.WithdrawGroupCreated,
|
||||||
withdrawalGroupId: withdrawalGroupId,
|
withdrawalGroupId: newWithdrawalGroup.withdrawalGroupId,
|
||||||
});
|
});
|
||||||
await processWithdrawGroup(ws, withdrawalGroupId);
|
await processWithdrawGroup(ws, newWithdrawalGroup.withdrawalGroupId);
|
||||||
} else {
|
} else {
|
||||||
console.trace("withdraw session already existed");
|
console.trace("withdraw session already existed");
|
||||||
}
|
}
|
||||||
|
130
src/operations/transactions.ts
Normal file
130
src/operations/transactions.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2019 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 { InternalWalletState } from "./state";
|
||||||
|
import { Stores, ProposalRecord, ReserveRecordStatus } from "../types/dbTypes";
|
||||||
|
import { Amounts } from "../util/amounts";
|
||||||
|
import { timestampCmp } from "../util/time";
|
||||||
|
import {
|
||||||
|
TransactionsRequest,
|
||||||
|
TransactionsResponse,
|
||||||
|
Transaction,
|
||||||
|
TransactionType,
|
||||||
|
} from "../types/transactions";
|
||||||
|
import { OrderShortInfo } from "../types/history";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an event ID from the type and the primary key for the event.
|
||||||
|
*/
|
||||||
|
function makeEventId(type: TransactionType, ...args: string[]): string {
|
||||||
|
return type + ";" + args.map((x) => encodeURIComponent(x)).join(";");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOrderShortInfo(
|
||||||
|
proposal: ProposalRecord,
|
||||||
|
): OrderShortInfo | undefined {
|
||||||
|
const download = proposal.download;
|
||||||
|
if (!download) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
amount: Amounts.stringify(download.contractData.amount),
|
||||||
|
fulfillmentUrl: download.contractData.fulfillmentUrl,
|
||||||
|
orderId: download.contractData.orderId,
|
||||||
|
merchantBaseUrl: download.contractData.merchantBaseUrl,
|
||||||
|
proposalId: proposal.proposalId,
|
||||||
|
summary: download.contractData.summary,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrive the full event history for this wallet.
|
||||||
|
*/
|
||||||
|
export async function getTransactions(
|
||||||
|
ws: InternalWalletState,
|
||||||
|
transactionsRequest?: TransactionsRequest,
|
||||||
|
): Promise<TransactionsResponse> {
|
||||||
|
const transactions: Transaction[] = [];
|
||||||
|
|
||||||
|
await ws.db.runWithReadTransaction(
|
||||||
|
[
|
||||||
|
Stores.currencies,
|
||||||
|
Stores.coins,
|
||||||
|
Stores.denominations,
|
||||||
|
Stores.proposals,
|
||||||
|
Stores.purchases,
|
||||||
|
Stores.refreshGroups,
|
||||||
|
Stores.reserves,
|
||||||
|
Stores.reserveHistory,
|
||||||
|
Stores.tips,
|
||||||
|
Stores.withdrawalGroups,
|
||||||
|
Stores.payEvents,
|
||||||
|
Stores.planchets,
|
||||||
|
Stores.refundEvents,
|
||||||
|
Stores.reserveUpdatedEvents,
|
||||||
|
Stores.recoupGroups,
|
||||||
|
],
|
||||||
|
async (tx) => {
|
||||||
|
tx.iter(Stores.withdrawalGroups).forEach((wsr) => {
|
||||||
|
if (wsr.timestampFinish) {
|
||||||
|
transactions.push({
|
||||||
|
type: TransactionType.Withdrawal,
|
||||||
|
amountEffective: Amounts.stringify(wsr.denomsSel.totalWithdrawCost),
|
||||||
|
amountRaw: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
||||||
|
confirmed: true,
|
||||||
|
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||||
|
pending: !wsr.timestampFinish,
|
||||||
|
timestamp: wsr.timestampStart,
|
||||||
|
transactionId: makeEventId(
|
||||||
|
TransactionType.Withdrawal,
|
||||||
|
wsr.withdrawalGroupId,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tx.iter(Stores.reserves).forEach((r) => {
|
||||||
|
if (r.reserveStatus !== ReserveRecordStatus.WAIT_CONFIRM_BANK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!r.bankInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
transactions.push({
|
||||||
|
type: TransactionType.Withdrawal,
|
||||||
|
confirmed: false,
|
||||||
|
amountRaw: Amounts.stringify(r.bankInfo.amount),
|
||||||
|
amountEffective: undefined,
|
||||||
|
exchangeBaseUrl: undefined,
|
||||||
|
pending: true,
|
||||||
|
timestamp: r.timestampCreated,
|
||||||
|
bankConfirmationUrl: r.bankInfo.confirmUrl,
|
||||||
|
transactionId: makeEventId(
|
||||||
|
TransactionType.Withdrawal,
|
||||||
|
r.bankInfo.bankWithdrawalGroupId,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
transactions.sort((h1, h2) => timestampCmp(h1.timestamp, h2.timestamp));
|
||||||
|
|
||||||
|
return { transactions };
|
||||||
|
}
|
@ -273,13 +273,17 @@ export interface ReserveRecord {
|
|||||||
*/
|
*/
|
||||||
exchangeWire: string;
|
exchangeWire: string;
|
||||||
|
|
||||||
bankWithdrawStatusUrl?: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL that the bank gave us to redirect the customer
|
* Extra state for when this is a withdrawal involving
|
||||||
* to in order to confirm a withdrawal.
|
* a Taler-integrated bank.
|
||||||
*/
|
*/
|
||||||
bankWithdrawConfirmUrl?: string;
|
bankInfo?: {
|
||||||
|
statusUrl: string;
|
||||||
|
confirmUrl?: string;
|
||||||
|
amount: AmountJson;
|
||||||
|
bankWithdrawalGroupId: string;
|
||||||
|
withdrawalStarted: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
reserveStatus: ReserveRecordStatus;
|
reserveStatus: ReserveRecordStatus;
|
||||||
|
|
||||||
|
208
src/types/transactions.ts
Normal file
208
src/types/transactions.ts
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2019 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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type and schema definitions for the wallet's transaction list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports.
|
||||||
|
*/
|
||||||
|
import { Timestamp } from "../util/time";
|
||||||
|
import { AmountString } from "./talerTypes";
|
||||||
|
|
||||||
|
export interface TransactionsRequest {
|
||||||
|
/**
|
||||||
|
* return only transactions in the given currency
|
||||||
|
*/
|
||||||
|
currency?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if present, results will be limited to transactions related to the given search string
|
||||||
|
*/
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionsResponse {
|
||||||
|
// a list of past and pending transactions sorted by pending, timestamp and transactionId.
|
||||||
|
// In case two events are both pending and have the same timestamp,
|
||||||
|
// they are sorted by the transactionId
|
||||||
|
// (lexically ascending and locale-independent comparison).
|
||||||
|
transactions: Transaction[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionCommon {
|
||||||
|
// opaque unique ID for the transaction, used as a starting point for paginating queries
|
||||||
|
// and for invoking actions on the transaction (e.g. deleting/hiding it from the history)
|
||||||
|
transactionId: string;
|
||||||
|
|
||||||
|
// the type of the transaction; different types might provide additional information
|
||||||
|
type: TransactionType;
|
||||||
|
|
||||||
|
// main timestamp of the transaction
|
||||||
|
timestamp: Timestamp;
|
||||||
|
|
||||||
|
// true if the transaction is still pending, false otherwise
|
||||||
|
// If a transaction is not longer pending, its timestamp will be updated,
|
||||||
|
// but its transactionId will remain unchanged
|
||||||
|
pending: boolean;
|
||||||
|
|
||||||
|
// Raw amount of the transaction (exclusive of fees or other extra costs)
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
// Amount added or removed from the wallet's balance (including all fees and other costs)
|
||||||
|
amountEffective?: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Transaction = (
|
||||||
|
TransactionWithdrawal |
|
||||||
|
TransactionPayment |
|
||||||
|
TransactionRefund |
|
||||||
|
TransactionTip |
|
||||||
|
TransactionRefresh
|
||||||
|
)
|
||||||
|
|
||||||
|
export const enum TransactionType {
|
||||||
|
Withdrawal = "withdrawal",
|
||||||
|
Payment = "payment",
|
||||||
|
Refund = "refund",
|
||||||
|
Refresh = "refresh",
|
||||||
|
Tip = "tip",
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should only be used for actual withdrawals
|
||||||
|
// and not for tips that have their own transactions type.
|
||||||
|
interface TransactionWithdrawal extends TransactionCommon {
|
||||||
|
type: TransactionType.Withdrawal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange of the withdrawal.
|
||||||
|
*/
|
||||||
|
exchangeBaseUrl?: string;
|
||||||
|
|
||||||
|
// true if the bank has confirmed the withdrawal, false if not.
|
||||||
|
// An unconfirmed withdrawal usually requires user-input and should be highlighted in the UI.
|
||||||
|
// See also bankConfirmationUrl below.
|
||||||
|
confirmed: boolean;
|
||||||
|
|
||||||
|
// If the withdrawal is unconfirmed, this can include a URL for user initiated confirmation.
|
||||||
|
bankConfirmationUrl?: string;
|
||||||
|
|
||||||
|
// Amount that has been subtracted from the reserve's balance for this withdrawal.
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount that actually was (or will be) added to the wallet's balance.
|
||||||
|
* Only present if an exchange has already been selected.
|
||||||
|
*/
|
||||||
|
amountEffective?: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TransactionPayment extends TransactionCommon {
|
||||||
|
type: TransactionType.Payment;
|
||||||
|
|
||||||
|
// Additional information about the payment.
|
||||||
|
info: TransactionInfo;
|
||||||
|
|
||||||
|
// true if the payment failed, false otherwise.
|
||||||
|
// Note that failed payments with zero effective amount will not be returned by the API.
|
||||||
|
failed: boolean;
|
||||||
|
|
||||||
|
// Amount that must be paid for the contract
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
// Amount that was paid, including deposit, wire and refresh fees.
|
||||||
|
amountEffective: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface TransactionInfo {
|
||||||
|
// Order ID, uniquely identifies the order within a merchant instance
|
||||||
|
orderId: string;
|
||||||
|
|
||||||
|
// More information about the merchant
|
||||||
|
merchant: any;
|
||||||
|
|
||||||
|
// Summary of the order, given by the merchant
|
||||||
|
summary: string;
|
||||||
|
|
||||||
|
// Map from IETF BCP 47 language tags to localized summaries
|
||||||
|
summary_i18n?: { [lang_tag: string]: string };
|
||||||
|
|
||||||
|
// List of products that are part of the order
|
||||||
|
products: any[];
|
||||||
|
|
||||||
|
// URL of the fulfillment, given by the merchant
|
||||||
|
fulfillmentUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface TransactionRefund extends TransactionCommon {
|
||||||
|
type: TransactionType.Refund;
|
||||||
|
|
||||||
|
// ID for the transaction that is refunded
|
||||||
|
refundedTransactionId: string;
|
||||||
|
|
||||||
|
// Additional information about the refunded payment
|
||||||
|
info: TransactionInfo;
|
||||||
|
|
||||||
|
// Part of the refund that couldn't be applied because the refund permissions were expired
|
||||||
|
amountInvalid: AmountString;
|
||||||
|
|
||||||
|
// Amount that has been refunded by the merchant
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
// Amount will be added to the wallet's balance after fees and refreshing
|
||||||
|
amountEffective: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TransactionTip extends TransactionCommon {
|
||||||
|
type: TransactionType.Tip;
|
||||||
|
|
||||||
|
// true if the user still needs to accept/decline this tip
|
||||||
|
waiting: boolean;
|
||||||
|
|
||||||
|
// true if the user has accepted this top, false otherwise
|
||||||
|
accepted: boolean;
|
||||||
|
|
||||||
|
// Exchange that the tip will be (or was) withdrawn from
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
|
// More information about the merchant that sent the tip
|
||||||
|
merchant: any;
|
||||||
|
|
||||||
|
// Raw amount of the tip, without extra fees that apply
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
// Amount will be (or was) added to the wallet's balance after fees and refreshing
|
||||||
|
amountEffective: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A transaction shown for refreshes that are not associated to other transactions
|
||||||
|
// such as a refresh necessary before coin expiration.
|
||||||
|
// It should only be returned by the API if the effective amount is different from zero.
|
||||||
|
interface TransactionRefresh extends TransactionCommon {
|
||||||
|
type: TransactionType.Refresh;
|
||||||
|
|
||||||
|
// Exchange that the coins are refreshed with
|
||||||
|
exchangeBaseUrl: string;
|
||||||
|
|
||||||
|
// Raw amount that is refreshed
|
||||||
|
amountRaw: AmountString;
|
||||||
|
|
||||||
|
// Amount that will be paid as fees for the refresh
|
||||||
|
amountEffective: AmountString;
|
||||||
|
}
|
@ -112,6 +112,8 @@ import {
|
|||||||
import { durationMin, Duration } from "./util/time";
|
import { durationMin, Duration } from "./util/time";
|
||||||
import { processRecoupGroup } from "./operations/recoup";
|
import { processRecoupGroup } from "./operations/recoup";
|
||||||
import { OperationFailedAndReportedError } from "./operations/errors";
|
import { OperationFailedAndReportedError } from "./operations/errors";
|
||||||
|
import { TransactionsRequest, TransactionsResponse } from "./types/transactions";
|
||||||
|
import { getTransactions } from "./operations/transactions";
|
||||||
|
|
||||||
const builtinCurrencies: CurrencyRecord[] = [
|
const builtinCurrencies: CurrencyRecord[] = [
|
||||||
{
|
{
|
||||||
@ -815,4 +817,8 @@ export class Wallet {
|
|||||||
}
|
}
|
||||||
return coinsJson;
|
return coinsJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTransactions(request: TransactionsRequest): Promise<TransactionsResponse> {
|
||||||
|
return getTransactions(this.ws, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user