wallet-core: towards DD37 for deposits
This commit is contained in:
parent
e331012c9f
commit
15feebecfe
@ -970,6 +970,19 @@ export class ExchangeService implements ExchangeServiceInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async runAggregatorOnceWithTimetravel(opts: {
|
||||||
|
timetravelMicroseconds: number;
|
||||||
|
}) {
|
||||||
|
let timetravelArgArr = [];
|
||||||
|
timetravelArgArr.push(`--timetravel=${opts.timetravelMicroseconds}`);
|
||||||
|
await runCommand(
|
||||||
|
this.globalState,
|
||||||
|
`exchange-${this.name}-aggregator-once`,
|
||||||
|
"taler-exchange-aggregator",
|
||||||
|
[...timetravelArgArr, "-c", this.configFilename, "-t"],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async runAggregatorOnce() {
|
async runAggregatorOnce() {
|
||||||
try {
|
try {
|
||||||
await runCommand(
|
await runCommand(
|
||||||
@ -1147,6 +1160,9 @@ export class ExchangeService implements ExchangeServiceInterface {
|
|||||||
exchangeHttpProc: ProcessWrapper | undefined;
|
exchangeHttpProc: ProcessWrapper | undefined;
|
||||||
exchangeWirewatchProc: ProcessWrapper | undefined;
|
exchangeWirewatchProc: ProcessWrapper | undefined;
|
||||||
|
|
||||||
|
exchangeTransferProc: ProcessWrapper | undefined;
|
||||||
|
exchangeAggregatorProc: ProcessWrapper | undefined;
|
||||||
|
|
||||||
helperCryptoRsaProc: ProcessWrapper | undefined;
|
helperCryptoRsaProc: ProcessWrapper | undefined;
|
||||||
helperCryptoEddsaProc: ProcessWrapper | undefined;
|
helperCryptoEddsaProc: ProcessWrapper | undefined;
|
||||||
helperCryptoCsProc: ProcessWrapper | undefined;
|
helperCryptoCsProc: ProcessWrapper | undefined;
|
||||||
@ -1200,6 +1216,18 @@ export class ExchangeService implements ExchangeServiceInterface {
|
|||||||
await wirewatch.wait();
|
await wirewatch.wait();
|
||||||
this.exchangeWirewatchProc = undefined;
|
this.exchangeWirewatchProc = undefined;
|
||||||
}
|
}
|
||||||
|
const aggregatorProc = this.exchangeAggregatorProc;
|
||||||
|
if (aggregatorProc) {
|
||||||
|
aggregatorProc.proc.kill("SIGTERM");
|
||||||
|
await aggregatorProc.wait();
|
||||||
|
this.exchangeAggregatorProc = undefined;
|
||||||
|
}
|
||||||
|
const transferProc = this.exchangeTransferProc;
|
||||||
|
if (transferProc) {
|
||||||
|
transferProc.proc.kill("SIGTERM");
|
||||||
|
await transferProc.wait();
|
||||||
|
this.exchangeTransferProc = undefined;
|
||||||
|
}
|
||||||
const httpd = this.exchangeHttpProc;
|
const httpd = this.exchangeHttpProc;
|
||||||
if (httpd) {
|
if (httpd) {
|
||||||
httpd.proc.kill("SIGTERM");
|
httpd.proc.kill("SIGTERM");
|
||||||
@ -1369,6 +1397,22 @@ export class ExchangeService implements ExchangeServiceInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private internalCreateAggregatorProc() {
|
||||||
|
this.exchangeAggregatorProc = this.globalState.spawnService(
|
||||||
|
"taler-exchange-aggregator",
|
||||||
|
["-c", this.configFilename, ...this.timetravelArgArr],
|
||||||
|
`exchange-aggregator-${this.name}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private internalCreateTransferProc() {
|
||||||
|
this.exchangeTransferProc = this.globalState.spawnService(
|
||||||
|
"taler-exchange-transfer",
|
||||||
|
["-c", this.configFilename, ...this.timetravelArgArr],
|
||||||
|
`exchange-transfer-${this.name}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
if (this.isRunning()) {
|
if (this.isRunning()) {
|
||||||
throw Error("exchange is already running");
|
throw Error("exchange is already running");
|
||||||
@ -1398,6 +1442,8 @@ export class ExchangeService implements ExchangeServiceInterface {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.internalCreateWirewatchProc();
|
this.internalCreateWirewatchProc();
|
||||||
|
this.internalCreateTransferProc();
|
||||||
|
this.internalCreateAggregatorProc();
|
||||||
|
|
||||||
this.exchangeHttpProc = this.globalState.spawnService(
|
this.exchangeHttpProc = this.globalState.spawnService(
|
||||||
"taler-exchange-httpd",
|
"taler-exchange-httpd",
|
||||||
@ -2062,7 +2108,7 @@ export class WalletService {
|
|||||||
[
|
[
|
||||||
"--wallet-db",
|
"--wallet-db",
|
||||||
dbPath,
|
dbPath,
|
||||||
"-LDEBUG", // FIXME: Make this configurable?
|
"-LTRACE", // FIXME: Make this configurable?
|
||||||
"--no-throttle", // FIXME: Optionally do throttling for some tests?
|
"--no-throttle", // FIXME: Optionally do throttling for some tests?
|
||||||
"advanced",
|
"advanced",
|
||||||
"serve",
|
"serve",
|
||||||
|
@ -47,7 +47,14 @@ import { lintExchangeDeployment } from "./lint.js";
|
|||||||
import { runEnvFull } from "./env-full.js";
|
import { runEnvFull } from "./env-full.js";
|
||||||
import { clk } from "@gnu-taler/taler-util/clk";
|
import { clk } from "@gnu-taler/taler-util/clk";
|
||||||
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
|
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
|
||||||
import { BankAccessApiClient } from "@gnu-taler/taler-wallet-core";
|
import {
|
||||||
|
BankAccessApiClient,
|
||||||
|
checkReserve,
|
||||||
|
CryptoDispatcher,
|
||||||
|
downloadExchangeInfo,
|
||||||
|
SynchronousCryptoWorkerFactoryPlain,
|
||||||
|
topupReserveWithDemobank,
|
||||||
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
|
|
||||||
const logger = new Logger("taler-harness:index.ts");
|
const logger = new Logger("taler-harness:index.ts");
|
||||||
|
|
||||||
@ -162,7 +169,6 @@ advancedCli
|
|||||||
await runTestWithState(testState, runEnv1, "env1", true);
|
await runTestWithState(testState, runEnv1, "env1", true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const sandcastleCli = testingCli.subcommand("sandcastleArgs", "sandcastle", {
|
const sandcastleCli = testingCli.subcommand("sandcastleArgs", "sandcastle", {
|
||||||
help: "Subcommands for handling GNU Taler sandcastle deployments.",
|
help: "Subcommands for handling GNU Taler sandcastle deployments.",
|
||||||
});
|
});
|
||||||
@ -260,6 +266,66 @@ deploymentCli
|
|||||||
// FIXME: Now delete reserves that are not filled yet
|
// FIXME: Now delete reserves that are not filled yet
|
||||||
});
|
});
|
||||||
|
|
||||||
|
deploymentCli
|
||||||
|
.subcommand("testTalerdotnetDemo", "test-demo-talerdotnet")
|
||||||
|
.action(async (args) => {
|
||||||
|
const http = createPlatformHttpLib();
|
||||||
|
const cryptiDisp = new CryptoDispatcher(
|
||||||
|
new SynchronousCryptoWorkerFactoryPlain(),
|
||||||
|
);
|
||||||
|
const cryptoApi = cryptiDisp.cryptoApi;
|
||||||
|
const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
|
||||||
|
const exchangeBaseUrl = "https://exchange.demo.taler.net/";
|
||||||
|
const exchangeInfo = await downloadExchangeInfo(exchangeBaseUrl, http);
|
||||||
|
await topupReserveWithDemobank({
|
||||||
|
amount: "KUDOS:10",
|
||||||
|
bankAccessApiBaseUrl:
|
||||||
|
"https://bank.demo.taler.net/demobanks/default/access-api/",
|
||||||
|
bankBaseUrl: "",
|
||||||
|
exchangeInfo,
|
||||||
|
http,
|
||||||
|
reservePub: reserveKeyPair.pub,
|
||||||
|
});
|
||||||
|
let reserveUrl = new URL(`reserves/${reserveKeyPair.pub}`, exchangeBaseUrl);
|
||||||
|
reserveUrl.searchParams.set("timeout_ms", "30000");
|
||||||
|
console.log("requesting", reserveUrl.href);
|
||||||
|
const longpollReq = http.fetch(reserveUrl.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const reserveStatusResp = await longpollReq;
|
||||||
|
console.log("reserve status", reserveStatusResp.status);
|
||||||
|
});
|
||||||
|
|
||||||
|
deploymentCli
|
||||||
|
.subcommand("testLocalhostDemo", "test-demo-localhost")
|
||||||
|
.action(async (args) => {
|
||||||
|
// Run checks against the "env-full" demo deployment on localhost
|
||||||
|
const http = createPlatformHttpLib();
|
||||||
|
const cryptiDisp = new CryptoDispatcher(
|
||||||
|
new SynchronousCryptoWorkerFactoryPlain(),
|
||||||
|
);
|
||||||
|
const cryptoApi = cryptiDisp.cryptoApi;
|
||||||
|
const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
|
||||||
|
const exchangeBaseUrl = "http://localhost:8081/";
|
||||||
|
const exchangeInfo = await downloadExchangeInfo(exchangeBaseUrl, http);
|
||||||
|
await topupReserveWithDemobank({
|
||||||
|
amount: "TESTKUDOS:10",
|
||||||
|
bankAccessApiBaseUrl: "http://localhost:8082/taler-bank-access/",
|
||||||
|
bankBaseUrl: "",
|
||||||
|
exchangeInfo,
|
||||||
|
http,
|
||||||
|
reservePub: reserveKeyPair.pub,
|
||||||
|
});
|
||||||
|
let reserveUrl = new URL(`reserves/${reserveKeyPair.pub}`, exchangeBaseUrl);
|
||||||
|
reserveUrl.searchParams.set("timeout_ms", "30000");
|
||||||
|
console.log("requesting", reserveUrl.href);
|
||||||
|
const longpollReq = http.fetch(reserveUrl.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
const reserveStatusResp = await longpollReq;
|
||||||
|
console.log("reserve status", reserveStatusResp.status);
|
||||||
|
});
|
||||||
|
|
||||||
deploymentCli
|
deploymentCli
|
||||||
.subcommand("tipStatus", "tip-status")
|
.subcommand("tipStatus", "tip-status")
|
||||||
.requiredOption("merchantBaseUrl", ["--merchant-url"], clk.STRING)
|
.requiredOption("merchantBaseUrl", ["--merchant-url"], clk.STRING)
|
||||||
|
@ -17,7 +17,11 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { NotificationType, TransactionState } from "@gnu-taler/taler-util";
|
import {
|
||||||
|
NotificationType,
|
||||||
|
TransactionMajorState,
|
||||||
|
TransactionMinorState,
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { GlobalTestState, getPayto } from "../harness/harness.js";
|
import { GlobalTestState, getPayto } from "../harness/harness.js";
|
||||||
import {
|
import {
|
||||||
@ -52,11 +56,19 @@ export async function runDepositTest(t: GlobalTestState) {
|
|||||||
|
|
||||||
const depositTxId = dgIdResp.transactionId;
|
const depositTxId = dgIdResp.transactionId;
|
||||||
|
|
||||||
|
const depositTrack = walletClient.waitForNotificationCond(
|
||||||
|
(n) =>
|
||||||
|
n.type == NotificationType.TransactionStateTransition &&
|
||||||
|
n.transactionId == depositTxId &&
|
||||||
|
n.newTxState.major == TransactionMajorState.Pending &&
|
||||||
|
n.newTxState.minor == TransactionMinorState.Track,
|
||||||
|
);
|
||||||
|
|
||||||
const depositDone = walletClient.waitForNotificationCond(
|
const depositDone = walletClient.waitForNotificationCond(
|
||||||
(n) =>
|
(n) =>
|
||||||
n.type == NotificationType.TransactionStateTransition &&
|
n.type == NotificationType.TransactionStateTransition &&
|
||||||
n.transactionId == depositTxId &&
|
n.transactionId == depositTxId &&
|
||||||
n.newTxState == TransactionState.Done,
|
n.newTxState.major == TransactionMajorState.Done,
|
||||||
);
|
);
|
||||||
|
|
||||||
const depositGroupResult = await walletClient.client.call(
|
const depositGroupResult = await walletClient.client.call(
|
||||||
@ -70,6 +82,12 @@ export async function runDepositTest(t: GlobalTestState) {
|
|||||||
|
|
||||||
t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
|
t.assertDeepEqual(depositGroupResult.transactionId, depositTxId);
|
||||||
|
|
||||||
|
await depositTrack;
|
||||||
|
|
||||||
|
await exchange.runAggregatorOnceWithTimetravel({
|
||||||
|
timetravelMicroseconds: 1000 * 1000 * 60 * 60 * 3,
|
||||||
|
});
|
||||||
|
|
||||||
await depositDone;
|
await depositDone;
|
||||||
|
|
||||||
const transactions = await walletClient.client.call(
|
const transactions = await walletClient.client.call(
|
||||||
|
@ -59,16 +59,29 @@ export async function runWalletDblessTest(t: GlobalTestState) {
|
|||||||
|
|
||||||
const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
|
const reserveKeyPair = await cryptoApi.createEddsaKeypair({});
|
||||||
|
|
||||||
await topupReserveWithDemobank(
|
let reserveUrl = new URL(
|
||||||
http,
|
`reserves/${reserveKeyPair.pub}`,
|
||||||
reserveKeyPair.pub,
|
exchange.baseUrl,
|
||||||
bank.baseUrl,
|
|
||||||
bank.bankAccessApiBaseUrl,
|
|
||||||
exchangeInfo,
|
|
||||||
"TESTKUDOS:10",
|
|
||||||
);
|
);
|
||||||
|
reserveUrl.searchParams.set("timeout_ms", "30000");
|
||||||
|
const longpollReq = http.fetch(reserveUrl.href, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
|
||||||
await exchange.runWirewatchOnce();
|
await topupReserveWithDemobank({
|
||||||
|
amount: "TESTKUDOS:10",
|
||||||
|
http,
|
||||||
|
reservePub: reserveKeyPair.pub,
|
||||||
|
bankAccessApiBaseUrl: bank.bankAccessApiBaseUrl,
|
||||||
|
bankBaseUrl: bank.baseUrl,
|
||||||
|
exchangeInfo,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("waiting for longpoll request");
|
||||||
|
const resp = await longpollReq;
|
||||||
|
console.log(`got response, status ${resp.status}`);
|
||||||
|
|
||||||
|
console.log(exchangeInfo);
|
||||||
|
|
||||||
await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub);
|
await checkReserve(http, exchange.baseUrl, reserveKeyPair.pub);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
/**
|
/**
|
||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import { TransactionState, TransactionSubstate } from "./transactions-types.js";
|
import { TransactionState } from "./transactions-types.js";
|
||||||
import { TalerErrorDetail } from "./wallet-types.js";
|
import { TalerErrorDetail } from "./wallet-types.js";
|
||||||
|
|
||||||
export enum NotificationType {
|
export enum NotificationType {
|
||||||
@ -75,9 +75,7 @@ export interface TransactionStateTransitionNotification {
|
|||||||
type: NotificationType.TransactionStateTransition;
|
type: NotificationType.TransactionStateTransition;
|
||||||
transactionId: string;
|
transactionId: string;
|
||||||
oldTxState: TransactionState;
|
oldTxState: TransactionState;
|
||||||
oldTxSubstate: TransactionSubstate;
|
|
||||||
newTxState: TransactionState;
|
newTxState: TransactionState;
|
||||||
newTxSubstate: TransactionSubstate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProposalAcceptedNotification {
|
export interface ProposalAcceptedNotification {
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
TransactionType,
|
TransactionType,
|
||||||
TransactionState,
|
|
||||||
TransactionSubstate,
|
|
||||||
PaymentStatus,
|
PaymentStatus,
|
||||||
ExtendedStatus,
|
ExtendedStatus,
|
||||||
|
TransactionMajorState,
|
||||||
} from "./transactions-types.js";
|
} from "./transactions-types.js";
|
||||||
import { RefreshReason } from "./wallet-types.js";
|
import { RefreshReason } from "./wallet-types.js";
|
||||||
|
|
||||||
@ -29,8 +28,9 @@ import { RefreshReason } from "./wallet-types.js";
|
|||||||
export const sampleWalletCoreTransactions = [
|
export const sampleWalletCoreTransactions = [
|
||||||
{
|
{
|
||||||
type: TransactionType.Payment,
|
type: TransactionType.Payment,
|
||||||
txState: TransactionState.Done,
|
txState: {
|
||||||
txSubstate: TransactionSubstate.None,
|
major: TransactionMajorState.Done,
|
||||||
|
},
|
||||||
amountRaw: "KUDOS:10",
|
amountRaw: "KUDOS:10",
|
||||||
amountEffective: "KUDOS:10",
|
amountEffective: "KUDOS:10",
|
||||||
totalRefundRaw: "KUDOS:0",
|
totalRefundRaw: "KUDOS:0",
|
||||||
@ -75,8 +75,9 @@ export const sampleWalletCoreTransactions = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: TransactionType.Refresh,
|
type: TransactionType.Refresh,
|
||||||
txState: TransactionState.Pending,
|
txState: {
|
||||||
txSubstate: TransactionSubstate.None,
|
major: TransactionMajorState.Pending,
|
||||||
|
},
|
||||||
refreshReason: RefreshReason.PayMerchant,
|
refreshReason: RefreshReason.PayMerchant,
|
||||||
amountEffective: "KUDOS:0",
|
amountEffective: "KUDOS:0",
|
||||||
amountRaw: "KUDOS:0",
|
amountRaw: "KUDOS:0",
|
||||||
|
@ -59,11 +59,6 @@ export enum ExtendedStatus {
|
|||||||
KycRequired = "kyc-required",
|
KycRequired = "kyc-required",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionStateInfo {
|
|
||||||
txState: TransactionState;
|
|
||||||
txSubstate: TransactionSubstate;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TransactionsRequest {
|
export interface TransactionsRequest {
|
||||||
/**
|
/**
|
||||||
* return only transactions in the given currency
|
* return only transactions in the given currency
|
||||||
@ -81,7 +76,12 @@ export interface TransactionsRequest {
|
|||||||
includeRefreshes?: boolean;
|
includeRefreshes?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TransactionState {
|
export interface TransactionState {
|
||||||
|
major: TransactionMajorState;
|
||||||
|
minor?: TransactionMinorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TransactionMajorState {
|
||||||
// No state, only used when reporting transitions into the initial state
|
// No state, only used when reporting transitions into the initial state
|
||||||
None = "none",
|
None = "none",
|
||||||
Pending = "pending",
|
Pending = "pending",
|
||||||
@ -96,15 +96,13 @@ export enum TransactionState {
|
|||||||
Unknown = "unknown",
|
Unknown = "unknown",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TransactionSubstate {
|
export enum TransactionMinorState {
|
||||||
// Placeholder until D37 is fully implemented
|
// Placeholder until D37 is fully implemented
|
||||||
Unknown = "unknown",
|
Unknown = "unknown",
|
||||||
// No substate
|
Deposit = "deposit",
|
||||||
None = "none",
|
KycRequired = "kyc-required",
|
||||||
DepositPendingInitial = "initial",
|
Track = "track",
|
||||||
DepositKycRequired = "kyc-required",
|
Refresh = "refresh",
|
||||||
DepositPendingTrack = "track",
|
|
||||||
DepositAbortingRefresh = "refresh",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransactionsResponse {
|
export interface TransactionsResponse {
|
||||||
@ -126,10 +124,11 @@ export interface TransactionCommon {
|
|||||||
// main timestamp of the transaction
|
// main timestamp of the transaction
|
||||||
timestamp: TalerProtocolTimestamp;
|
timestamp: TalerProtocolTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transaction state, as per DD37.
|
||||||
|
*/
|
||||||
txState: TransactionState;
|
txState: TransactionState;
|
||||||
|
|
||||||
txSubstate: TransactionSubstate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated in favor of statusMajor and statusMinor
|
* @deprecated in favor of statusMajor and statusMinor
|
||||||
*/
|
*/
|
||||||
|
@ -865,8 +865,10 @@ export enum DepositGroupOperationStatus {
|
|||||||
AbortingWithRefresh = 11 /* ACTIVE_START + 1 */,
|
AbortingWithRefresh = 11 /* ACTIVE_START + 1 */,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Improve name! This enum is very specific to deposits.
|
/**
|
||||||
export enum TransactionStatus {
|
* Status of a single element of a deposit group.
|
||||||
|
*/
|
||||||
|
export enum DepositElementStatus {
|
||||||
Unknown = 10,
|
Unknown = 10,
|
||||||
Accepted = 20,
|
Accepted = 20,
|
||||||
KycRequired = 30,
|
KycRequired = 30,
|
||||||
@ -1686,7 +1688,7 @@ export interface DepositGroupRecord {
|
|||||||
|
|
||||||
operationStatus: OperationStatus;
|
operationStatus: OperationStatus;
|
||||||
|
|
||||||
transactionPerCoin: TransactionStatus[];
|
transactionPerCoin: DepositElementStatus[];
|
||||||
|
|
||||||
trackingState?: {
|
trackingState?: {
|
||||||
[signature: string]: {
|
[signature: string]: {
|
||||||
@ -2605,7 +2607,7 @@ export const walletDbFixups: FixupDescription[] = [
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dg.transactionPerCoin = dg.depositedPerCoin.map(
|
dg.transactionPerCoin = dg.depositedPerCoin.map(
|
||||||
(c) => TransactionStatus.Unknown,
|
(c) => DepositElementStatus.Unknown,
|
||||||
);
|
);
|
||||||
await tx.depositGroups.put(dg);
|
await tx.depositGroups.put(dg);
|
||||||
});
|
});
|
||||||
|
@ -109,14 +109,26 @@ export async function checkReserve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TopupReserveWithDemobankArgs {
|
||||||
|
http: HttpRequestLibrary;
|
||||||
|
reservePub: string;
|
||||||
|
bankBaseUrl: string;
|
||||||
|
bankAccessApiBaseUrl: string;
|
||||||
|
exchangeInfo: ExchangeInfo;
|
||||||
|
amount: AmountString;
|
||||||
|
}
|
||||||
|
|
||||||
export async function topupReserveWithDemobank(
|
export async function topupReserveWithDemobank(
|
||||||
http: HttpRequestLibrary,
|
args: TopupReserveWithDemobankArgs,
|
||||||
reservePub: string,
|
|
||||||
bankBaseUrl: string,
|
|
||||||
bankAccessApiBaseUrl: string,
|
|
||||||
exchangeInfo: ExchangeInfo,
|
|
||||||
amount: AmountString,
|
|
||||||
) {
|
) {
|
||||||
|
const {
|
||||||
|
bankBaseUrl,
|
||||||
|
http,
|
||||||
|
bankAccessApiBaseUrl,
|
||||||
|
amount,
|
||||||
|
exchangeInfo,
|
||||||
|
reservePub,
|
||||||
|
} = args;
|
||||||
const bankHandle: BankServiceHandle = {
|
const bankHandle: BankServiceHandle = {
|
||||||
baseUrl: bankBaseUrl,
|
baseUrl: bankBaseUrl,
|
||||||
bankAccessApiBaseUrl: bankAccessApiBaseUrl,
|
bankAccessApiBaseUrl: bankAccessApiBaseUrl,
|
||||||
|
@ -40,6 +40,7 @@ import {
|
|||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
MerchantContractTerms,
|
MerchantContractTerms,
|
||||||
|
NotificationType,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
PayCoinSelection,
|
PayCoinSelection,
|
||||||
PrepareDepositRequest,
|
PrepareDepositRequest,
|
||||||
@ -49,9 +50,9 @@ import {
|
|||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp,
|
||||||
TrackTransaction,
|
TrackTransaction,
|
||||||
|
TransactionMajorState,
|
||||||
|
TransactionMinorState,
|
||||||
TransactionState,
|
TransactionState,
|
||||||
TransactionStateInfo,
|
|
||||||
TransactionSubstate,
|
|
||||||
TransactionType,
|
TransactionType,
|
||||||
URL,
|
URL,
|
||||||
WireFee,
|
WireFee,
|
||||||
@ -60,13 +61,16 @@ import {
|
|||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
DepositGroupRecord,
|
DepositGroupRecord,
|
||||||
OperationStatus,
|
OperationStatus,
|
||||||
TransactionStatus,
|
DepositElementStatus,
|
||||||
} from "../db.js";
|
} from "../db.js";
|
||||||
import { TalerError } from "@gnu-taler/taler-util";
|
import { TalerError } from "@gnu-taler/taler-util";
|
||||||
import { getTotalRefreshCost, KycPendingInfo, KycUserType } from "../index.js";
|
import { getTotalRefreshCost, KycPendingInfo, KycUserType } from "../index.js";
|
||||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||||
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
|
||||||
import { OperationAttemptResult } from "../util/retries.js";
|
import {
|
||||||
|
OperationAttemptResult,
|
||||||
|
OperationAttemptResultType,
|
||||||
|
} from "../util/retries.js";
|
||||||
import { spendCoins } from "./common.js";
|
import { spendCoins } from "./common.js";
|
||||||
import { getExchangeDetails } from "./exchanges.js";
|
import { getExchangeDetails } from "./exchanges.js";
|
||||||
import {
|
import {
|
||||||
@ -89,15 +93,13 @@ const logger = new Logger("deposits.ts");
|
|||||||
* Get the (DD37-style) transaction status based on the
|
* Get the (DD37-style) transaction status based on the
|
||||||
* database record of a deposit group.
|
* database record of a deposit group.
|
||||||
*/
|
*/
|
||||||
export async function computeDepositTransactionStatus(
|
export function computeDepositTransactionStatus(
|
||||||
ws: InternalWalletState,
|
|
||||||
dg: DepositGroupRecord,
|
dg: DepositGroupRecord,
|
||||||
): Promise<TransactionStateInfo> {
|
): TransactionState {
|
||||||
switch (dg.operationStatus) {
|
switch (dg.operationStatus) {
|
||||||
case OperationStatus.Finished: {
|
case OperationStatus.Finished: {
|
||||||
return {
|
return {
|
||||||
txState: TransactionState.Done,
|
major: TransactionMajorState.Done,
|
||||||
txSubstate: TransactionSubstate.None,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case OperationStatus.Pending: {
|
case OperationStatus.Pending: {
|
||||||
@ -110,10 +112,10 @@ export async function computeDepositTransactionStatus(
|
|||||||
numDeposited++;
|
numDeposited++;
|
||||||
}
|
}
|
||||||
switch (dg.transactionPerCoin[i]) {
|
switch (dg.transactionPerCoin[i]) {
|
||||||
case TransactionStatus.KycRequired:
|
case DepositElementStatus.KycRequired:
|
||||||
numKycRequired++;
|
numKycRequired++;
|
||||||
break;
|
break;
|
||||||
case TransactionStatus.Wired:
|
case DepositElementStatus.Wired:
|
||||||
numWired++;
|
numWired++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -121,21 +123,21 @@ export async function computeDepositTransactionStatus(
|
|||||||
|
|
||||||
if (numKycRequired > 0) {
|
if (numKycRequired > 0) {
|
||||||
return {
|
return {
|
||||||
txState: TransactionState.Pending,
|
major: TransactionMajorState.Pending,
|
||||||
txSubstate: TransactionSubstate.DepositKycRequired,
|
minor: TransactionMinorState.KycRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numDeposited == numTotal) {
|
if (numDeposited == numTotal) {
|
||||||
return {
|
return {
|
||||||
txState: TransactionState.Pending,
|
major: TransactionMajorState.Pending,
|
||||||
txSubstate: TransactionSubstate.DepositPendingTrack,
|
minor: TransactionMinorState.Track,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
txState: TransactionState.Pending,
|
major: TransactionMajorState.Pending,
|
||||||
txSubstate: TransactionSubstate.DepositPendingInitial,
|
minor: TransactionMinorState.Deposit,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -221,6 +223,13 @@ export async function processDepositGroup(
|
|||||||
return OperationAttemptResult.finishedEmpty();
|
return OperationAttemptResult.finishedEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transactionId = constructTransactionIdentifier({
|
||||||
|
tag: TransactionType.Deposit,
|
||||||
|
depositGroupId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const txStateOld = computeDepositTransactionStatus(depositGroup);
|
||||||
|
|
||||||
const contractData = extractContractData(
|
const contractData = extractContractData(
|
||||||
depositGroup.contractTermsRaw,
|
depositGroup.contractTermsRaw,
|
||||||
depositGroup.contractTermsHash,
|
depositGroup.contractTermsHash,
|
||||||
@ -239,7 +248,7 @@ export async function processDepositGroup(
|
|||||||
for (let i = 0; i < depositPermissions.length; i++) {
|
for (let i = 0; i < depositPermissions.length; i++) {
|
||||||
const perm = depositPermissions[i];
|
const perm = depositPermissions[i];
|
||||||
|
|
||||||
let updatedDeposit: boolean | undefined = undefined;
|
let updatedDeposit: boolean = false;
|
||||||
|
|
||||||
if (!depositGroup.depositedPerCoin[i]) {
|
if (!depositGroup.depositedPerCoin[i]) {
|
||||||
const requestBody: ExchangeDepositRequest = {
|
const requestBody: ExchangeDepositRequest = {
|
||||||
@ -270,7 +279,7 @@ export async function processDepositGroup(
|
|||||||
updatedDeposit = true;
|
updatedDeposit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatedTxStatus: TransactionStatus | undefined = undefined;
|
let updatedTxStatus: DepositElementStatus | undefined = undefined;
|
||||||
type ValueOf<T> = T[keyof T];
|
type ValueOf<T> = T[keyof T];
|
||||||
|
|
||||||
let newWiredTransaction:
|
let newWiredTransaction:
|
||||||
@ -280,12 +289,12 @@ export async function processDepositGroup(
|
|||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) {
|
if (depositGroup.transactionPerCoin[i] !== DepositElementStatus.Wired) {
|
||||||
const track = await trackDepositPermission(ws, depositGroup, perm);
|
const track = await trackDeposit(ws, depositGroup, perm);
|
||||||
|
|
||||||
if (track.type === "accepted") {
|
if (track.type === "accepted") {
|
||||||
if (!track.kyc_ok && track.requirement_row !== undefined) {
|
if (!track.kyc_ok && track.requirement_row !== undefined) {
|
||||||
updatedTxStatus = TransactionStatus.KycRequired;
|
updatedTxStatus = DepositElementStatus.KycRequired;
|
||||||
const { requirement_row: requirementRow } = track;
|
const { requirement_row: requirementRow } = track;
|
||||||
const paytoHash = encodeCrock(
|
const paytoHash = encodeCrock(
|
||||||
hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
|
hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
|
||||||
@ -297,10 +306,10 @@ export async function processDepositGroup(
|
|||||||
"individual",
|
"individual",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
updatedTxStatus = TransactionStatus.Accepted;
|
updatedTxStatus = DepositElementStatus.Accepted;
|
||||||
}
|
}
|
||||||
} else if (track.type === "wired") {
|
} else if (track.type === "wired") {
|
||||||
updatedTxStatus = TransactionStatus.Wired;
|
updatedTxStatus = DepositElementStatus.Wired;
|
||||||
|
|
||||||
const payto = parsePaytoUri(depositGroup.wire.payto_uri);
|
const payto = parsePaytoUri(depositGroup.wire.payto_uri);
|
||||||
if (!payto) {
|
if (!payto) {
|
||||||
@ -327,11 +336,11 @@ export async function processDepositGroup(
|
|||||||
id: track.exchange_sig,
|
id: track.exchange_sig,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
updatedTxStatus = TransactionStatus.Unknown;
|
updatedTxStatus = DepositElementStatus.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatedTxStatus !== undefined || updatedDeposit !== undefined) {
|
if (updatedTxStatus !== undefined || updatedDeposit) {
|
||||||
await ws.db
|
await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
@ -358,18 +367,18 @@ export async function processDepositGroup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await ws.db
|
const txStatusNew = await ws.db
|
||||||
.mktx((x) => [x.depositGroups])
|
.mktx((x) => [x.depositGroups])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const dg = await tx.depositGroups.get(depositGroupId);
|
const dg = await tx.depositGroups.get(depositGroupId);
|
||||||
if (!dg) {
|
if (!dg) {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
let allDepositedAndWired = true;
|
let allDepositedAndWired = true;
|
||||||
for (let i = 0; i < depositGroup.depositedPerCoin.length; i++) {
|
for (let i = 0; i < depositGroup.depositedPerCoin.length; i++) {
|
||||||
if (
|
if (
|
||||||
!depositGroup.depositedPerCoin[i] ||
|
!depositGroup.depositedPerCoin[i] ||
|
||||||
depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired
|
depositGroup.transactionPerCoin[i] !== DepositElementStatus.Wired
|
||||||
) {
|
) {
|
||||||
allDepositedAndWired = false;
|
allDepositedAndWired = false;
|
||||||
break;
|
break;
|
||||||
@ -380,8 +389,36 @@ export async function processDepositGroup(
|
|||||||
dg.operationStatus = OperationStatus.Finished;
|
dg.operationStatus = OperationStatus.Finished;
|
||||||
await tx.depositGroups.put(dg);
|
await tx.depositGroups.put(dg);
|
||||||
}
|
}
|
||||||
|
return computeDepositTransactionStatus(dg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!txStatusNew) {
|
||||||
|
// Doesn't exist anymore!
|
||||||
return OperationAttemptResult.finishedEmpty();
|
return OperationAttemptResult.finishedEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify if state transitioned
|
||||||
|
if (
|
||||||
|
txStateOld.major !== txStatusNew.major ||
|
||||||
|
txStateOld.minor !== txStatusNew.minor
|
||||||
|
) {
|
||||||
|
ws.notify({
|
||||||
|
type: NotificationType.TransactionStateTransition,
|
||||||
|
transactionId,
|
||||||
|
oldTxState: txStateOld,
|
||||||
|
newTxState: txStatusNew,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: consider other cases like aborting, suspend, ...
|
||||||
|
if (
|
||||||
|
txStatusNew.major === TransactionMajorState.Pending ||
|
||||||
|
txStatusNew.major === TransactionMajorState.Aborting
|
||||||
|
) {
|
||||||
|
return OperationAttemptResult.pendingEmpty();
|
||||||
|
} else {
|
||||||
|
return OperationAttemptResult.finishedEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getExchangeWireFee(
|
async function getExchangeWireFee(
|
||||||
@ -428,7 +465,7 @@ async function getExchangeWireFee(
|
|||||||
return fee;
|
return fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function trackDepositPermission(
|
async function trackDeposit(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
depositGroup: DepositGroupRecord,
|
depositGroup: DepositGroupRecord,
|
||||||
dp: CoinDepositPermission,
|
dp: CoinDepositPermission,
|
||||||
@ -448,6 +485,7 @@ async function trackDepositPermission(
|
|||||||
});
|
});
|
||||||
url.searchParams.set("merchant_sig", sigResp.sig);
|
url.searchParams.set("merchant_sig", sigResp.sig);
|
||||||
const httpResp = await ws.http.fetch(url.href, { method: "GET" });
|
const httpResp = await ws.http.fetch(url.href, { method: "GET" });
|
||||||
|
logger.trace(`deposits response status: ${httpResp.status}`);
|
||||||
switch (httpResp.status) {
|
switch (httpResp.status) {
|
||||||
case HttpStatusCode.Accepted: {
|
case HttpStatusCode.Accepted: {
|
||||||
const accepted = await readSuccessResponseJsonOrThrow(
|
const accepted = await readSuccessResponseJsonOrThrow(
|
||||||
@ -710,7 +748,7 @@ export async function createDepositGroup(
|
|||||||
timestampCreated: AbsoluteTime.toTimestamp(now),
|
timestampCreated: AbsoluteTime.toTimestamp(now),
|
||||||
timestampFinished: undefined,
|
timestampFinished: undefined,
|
||||||
transactionPerCoin: payCoinSel.coinSel.coinPubs.map(
|
transactionPerCoin: payCoinSel.coinSel.coinPubs.map(
|
||||||
() => TransactionStatus.Unknown,
|
() => DepositElementStatus.Unknown,
|
||||||
),
|
),
|
||||||
payCoinSelection: payCoinSel.coinSel,
|
payCoinSelection: payCoinSel.coinSel,
|
||||||
payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
|
payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
|
||||||
@ -733,7 +771,7 @@ export async function createDepositGroup(
|
|||||||
depositGroupId,
|
depositGroupId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await ws.db
|
const newTxState = await ws.db
|
||||||
.mktx((x) => [
|
.mktx((x) => [
|
||||||
x.depositGroups,
|
x.depositGroups,
|
||||||
x.coins,
|
x.coins,
|
||||||
@ -752,6 +790,16 @@ export async function createDepositGroup(
|
|||||||
refreshReason: RefreshReason.PayDeposit,
|
refreshReason: RefreshReason.PayDeposit,
|
||||||
});
|
});
|
||||||
await tx.depositGroups.put(depositGroup);
|
await tx.depositGroups.put(depositGroup);
|
||||||
|
return computeDepositTransactionStatus(depositGroup);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.notify({
|
||||||
|
type: NotificationType.TransactionStateTransition,
|
||||||
|
transactionId,
|
||||||
|
oldTxState: {
|
||||||
|
major: TransactionMajorState.None,
|
||||||
|
},
|
||||||
|
newTxState,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -35,10 +35,9 @@ import {
|
|||||||
Transaction,
|
Transaction,
|
||||||
TransactionByIdRequest,
|
TransactionByIdRequest,
|
||||||
TransactionIdStr,
|
TransactionIdStr,
|
||||||
|
TransactionMajorState,
|
||||||
TransactionsRequest,
|
TransactionsRequest,
|
||||||
TransactionsResponse,
|
TransactionsResponse,
|
||||||
TransactionState,
|
|
||||||
TransactionSubstate,
|
|
||||||
TransactionType,
|
TransactionType,
|
||||||
WithdrawalType,
|
WithdrawalType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
@ -58,7 +57,7 @@ import {
|
|||||||
WalletContractData,
|
WalletContractData,
|
||||||
PeerPushPaymentInitiationStatus,
|
PeerPushPaymentInitiationStatus,
|
||||||
PeerPullPaymentIncomingStatus,
|
PeerPullPaymentIncomingStatus,
|
||||||
TransactionStatus,
|
DepositElementStatus,
|
||||||
WithdrawalGroupStatus,
|
WithdrawalGroupStatus,
|
||||||
RefreshGroupRecord,
|
RefreshGroupRecord,
|
||||||
RefreshOperationStatus,
|
RefreshOperationStatus,
|
||||||
@ -79,7 +78,10 @@ import {
|
|||||||
runOperationWithErrorReporting,
|
runOperationWithErrorReporting,
|
||||||
TombstoneTag,
|
TombstoneTag,
|
||||||
} from "./common.js";
|
} from "./common.js";
|
||||||
import { processDepositGroup } from "./deposits.js";
|
import {
|
||||||
|
computeDepositTransactionStatus,
|
||||||
|
processDepositGroup,
|
||||||
|
} from "./deposits.js";
|
||||||
import { getExchangeDetails } from "./exchanges.js";
|
import { getExchangeDetails } from "./exchanges.js";
|
||||||
import {
|
import {
|
||||||
abortPay,
|
abortPay,
|
||||||
@ -425,6 +427,11 @@ export async function getTransactionById(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Just a marker helper for unknown states until DD37 is fully implemented.
|
||||||
|
const mkTxStateUnknown = () => ({
|
||||||
|
major: TransactionMajorState.Unknown,
|
||||||
|
});
|
||||||
|
|
||||||
function buildTransactionForPushPaymentDebit(
|
function buildTransactionForPushPaymentDebit(
|
||||||
pi: PeerPushPaymentInitiationRecord,
|
pi: PeerPushPaymentInitiationRecord,
|
||||||
contractTerms: PeerContractTerms,
|
contractTerms: PeerContractTerms,
|
||||||
@ -432,8 +439,7 @@ function buildTransactionForPushPaymentDebit(
|
|||||||
): Transaction {
|
): Transaction {
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPushDebit,
|
type: TransactionType.PeerPushDebit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: pi.totalCost,
|
amountEffective: pi.totalCost,
|
||||||
amountRaw: pi.amount,
|
amountRaw: pi.amount,
|
||||||
exchangeBaseUrl: pi.exchangeBaseUrl,
|
exchangeBaseUrl: pi.exchangeBaseUrl,
|
||||||
@ -466,8 +472,7 @@ function buildTransactionForPullPaymentDebit(
|
|||||||
): Transaction {
|
): Transaction {
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPullDebit,
|
type: TransactionType.PeerPullDebit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: pi.coinSel?.totalCost
|
amountEffective: pi.coinSel?.totalCost
|
||||||
? pi.coinSel?.totalCost
|
? pi.coinSel?.totalCost
|
||||||
: Amounts.stringify(pi.contractTerms.amount),
|
: Amounts.stringify(pi.contractTerms.amount),
|
||||||
@ -517,8 +522,7 @@ function buildTransactionForPeerPullCredit(
|
|||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPullCredit,
|
type: TransactionType.PeerPullCredit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
||||||
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
||||||
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||||
@ -553,8 +557,7 @@ function buildTransactionForPeerPullCredit(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPullCredit,
|
type: TransactionType.PeerPullCredit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),
|
amountEffective: Amounts.stringify(pullCredit.estimatedAmountEffective),
|
||||||
amountRaw: Amounts.stringify(peerContractTerms.amount),
|
amountRaw: Amounts.stringify(peerContractTerms.amount),
|
||||||
exchangeBaseUrl: pullCredit.exchangeBaseUrl,
|
exchangeBaseUrl: pullCredit.exchangeBaseUrl,
|
||||||
@ -593,8 +596,7 @@ function buildTransactionForPeerPushCredit(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPushCredit,
|
type: TransactionType.PeerPushCredit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
||||||
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
||||||
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||||
@ -618,8 +620,7 @@ function buildTransactionForPeerPushCredit(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.PeerPushCredit,
|
type: TransactionType.PeerPushCredit,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
// FIXME: This is wrong, needs to consider fees!
|
// FIXME: This is wrong, needs to consider fees!
|
||||||
amountEffective: Amounts.stringify(peerContractTerms.amount),
|
amountEffective: Amounts.stringify(peerContractTerms.amount),
|
||||||
amountRaw: Amounts.stringify(peerContractTerms.amount),
|
amountRaw: Amounts.stringify(peerContractTerms.amount),
|
||||||
@ -649,8 +650,7 @@ function buildTransactionForBankIntegratedWithdraw(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Withdrawal,
|
type: TransactionType.Withdrawal,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
||||||
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
||||||
withdrawalDetails: {
|
withdrawalDetails: {
|
||||||
@ -696,8 +696,7 @@ function buildTransactionForManualWithdraw(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Withdrawal,
|
type: TransactionType.Withdrawal,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(
|
amountEffective: Amounts.stringify(
|
||||||
withdrawalGroup.denomsSel.totalCoinValue,
|
withdrawalGroup.denomsSel.totalCoinValue,
|
||||||
),
|
),
|
||||||
@ -748,8 +747,7 @@ function buildTransactionForRefresh(
|
|||||||
).amount;
|
).amount;
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Refresh,
|
type: TransactionType.Refresh,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
refreshReason: refreshGroupRecord.reason,
|
refreshReason: refreshGroupRecord.reason,
|
||||||
amountEffective: Amounts.stringify(
|
amountEffective: Amounts.stringify(
|
||||||
Amounts.zeroOfCurrency(refreshGroupRecord.currency),
|
Amounts.zeroOfCurrency(refreshGroupRecord.currency),
|
||||||
@ -791,8 +789,7 @@ function buildTransactionForDeposit(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Deposit,
|
type: TransactionType.Deposit,
|
||||||
txState: TransactionState.Unknown,
|
txState: computeDepositTransactionStatus(dg),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
|
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
|
||||||
amountEffective: Amounts.stringify(dg.totalPayCost),
|
amountEffective: Amounts.stringify(dg.totalPayCost),
|
||||||
extendedStatus: dg.timestampFinished
|
extendedStatus: dg.timestampFinished
|
||||||
@ -810,7 +807,7 @@ function buildTransactionForDeposit(
|
|||||||
wireTransferProgress:
|
wireTransferProgress:
|
||||||
(100 *
|
(100 *
|
||||||
dg.transactionPerCoin.reduce(
|
dg.transactionPerCoin.reduce(
|
||||||
(prev, cur) => prev + (cur === TransactionStatus.Wired ? 1 : 0),
|
(prev, cur) => prev + (cur === DepositElementStatus.Wired ? 1 : 0),
|
||||||
0,
|
0,
|
||||||
)) /
|
)) /
|
||||||
dg.transactionPerCoin.length,
|
dg.transactionPerCoin.length,
|
||||||
@ -829,8 +826,7 @@ function buildTransactionForTip(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Tip,
|
type: TransactionType.Tip,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
|
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
|
||||||
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
|
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
|
||||||
extendedStatus: tipRecord.pickedUpTimestamp
|
extendedStatus: tipRecord.pickedUpTimestamp
|
||||||
@ -926,8 +922,7 @@ async function buildTransactionForRefund(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Refund,
|
type: TransactionType.Refund,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
info,
|
info,
|
||||||
refundedTransactionId: makeTransactionId(
|
refundedTransactionId: makeTransactionId(
|
||||||
TransactionType.Payment,
|
TransactionType.Payment,
|
||||||
@ -1030,8 +1025,7 @@ async function buildTransactionForPurchase(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: TransactionType.Payment,
|
type: TransactionType.Payment,
|
||||||
txState: TransactionState.Unknown,
|
txState: mkTxStateUnknown(),
|
||||||
txSubstate: TransactionSubstate.Unknown,
|
|
||||||
amountRaw: Amounts.stringify(contractData.amount),
|
amountRaw: Amounts.stringify(contractData.amount),
|
||||||
amountEffective: Amounts.stringify(purchaseRecord.payInfo.totalPayCost),
|
amountEffective: Amounts.stringify(purchaseRecord.payInfo.totalPayCost),
|
||||||
totalRefundRaw: Amounts.stringify(totalRefund.raw),
|
totalRefundRaw: Amounts.stringify(totalRefund.raw),
|
||||||
|
@ -70,6 +70,12 @@ export namespace OperationAttemptResult {
|
|||||||
result: undefined,
|
result: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export function pendingEmpty(): OperationAttemptResult<unknown, unknown> {
|
||||||
|
return {
|
||||||
|
type: OperationAttemptResultType.Pending,
|
||||||
|
result: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OperationAttemptFinishedResult<T> {
|
export interface OperationAttemptFinishedResult<T> {
|
||||||
|
Loading…
Reference in New Issue
Block a user