query transaction status for deposit
This commit is contained in:
parent
e034f1045c
commit
fc38d0da95
@ -850,6 +850,13 @@ export enum RefreshOperationStatus {
|
||||
FinishedWithError = 51 /* DORMANT_START + 1 */,
|
||||
}
|
||||
|
||||
export enum TransactionStatus {
|
||||
Unknown = 10,
|
||||
Accepted = 20,
|
||||
KycRequired = 30,
|
||||
Wired = 40,
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional information about the reason of a refresh.
|
||||
*/
|
||||
@ -1652,6 +1659,8 @@ export interface DepositGroupRecord {
|
||||
timestampFinished: TalerProtocolTimestamp | undefined;
|
||||
|
||||
operationStatus: OperationStatus;
|
||||
|
||||
transactionPerCoin: TransactionStatus[];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2416,6 +2425,20 @@ export const walletDbFixups: FixupDescription[] = [
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DepositGroupRecord_transactionPerCoin",
|
||||
async fn(tx): Promise<void> {
|
||||
await tx.depositGroups.iter().forEachAsync(async (dg) => {
|
||||
if (dg.transactionPerCoin) {
|
||||
return;
|
||||
}
|
||||
dg.transactionPerCoin = dg.depositedPerCoin.map(
|
||||
(c) => TransactionStatus.Unknown,
|
||||
);
|
||||
await tx.depositGroups.put(dg);
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const logger = new Logger("db.ts");
|
||||
|
@ -24,7 +24,9 @@ import {
|
||||
CancellationToken,
|
||||
canonicalJson,
|
||||
codecForDepositSuccess,
|
||||
MerchantContractTerms,
|
||||
codecForTackTransactionAccepted,
|
||||
codecForTackTransactionWired,
|
||||
CoinDepositPermission,
|
||||
CreateDepositGroupRequest,
|
||||
CreateDepositGroupResponse,
|
||||
DepositGroupFees,
|
||||
@ -34,23 +36,27 @@ import {
|
||||
GetFeeForDepositRequest,
|
||||
getRandomBytes,
|
||||
hashWire,
|
||||
HttpStatusCode,
|
||||
Logger,
|
||||
MerchantContractTerms,
|
||||
parsePaytoUri,
|
||||
PayCoinSelection,
|
||||
PrepareDepositRequest,
|
||||
PrepareDepositResponse,
|
||||
RefreshReason,
|
||||
TalerErrorCode,
|
||||
TalerProtocolTimestamp,
|
||||
TrackDepositGroupRequest,
|
||||
TrackDepositGroupResponse,
|
||||
TrackTransaction,
|
||||
TransactionType,
|
||||
URL,
|
||||
TalerErrorCode,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
DenominationRecord,
|
||||
DepositGroupRecord,
|
||||
OperationStatus,
|
||||
TransactionStatus,
|
||||
} from "../db.js";
|
||||
import { TalerError } from "../errors.js";
|
||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||
@ -111,10 +117,12 @@ export async function processDepositGroup(
|
||||
);
|
||||
|
||||
for (let i = 0; i < depositPermissions.length; i++) {
|
||||
if (depositGroup.depositedPerCoin[i]) {
|
||||
continue;
|
||||
}
|
||||
const perm = depositPermissions[i];
|
||||
|
||||
let updatedDeposit: boolean | undefined = undefined;
|
||||
let updatedTxStatus: TransactionStatus | undefined = undefined;
|
||||
|
||||
if (!depositGroup.depositedPerCoin[i]) {
|
||||
const requestBody: ExchangeDepositRequest = {
|
||||
contribution: Amounts.stringify(perm.contribution),
|
||||
merchant_payto_uri: depositGroup.wire.payto_uri,
|
||||
@ -138,6 +146,15 @@ export async function processDepositGroup(
|
||||
cancellationToken: options.cancellationToken,
|
||||
});
|
||||
await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess());
|
||||
updatedDeposit = true;
|
||||
}
|
||||
|
||||
if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) {
|
||||
const track = await trackDepositPermission(ws, depositGroup, perm);
|
||||
updatedTxStatus = txStatusFromTrack(track);
|
||||
}
|
||||
|
||||
if (updatedTxStatus !== undefined || updatedDeposit !== undefined) {
|
||||
await ws.db
|
||||
.mktx((x) => [x.depositGroups])
|
||||
.runReadWrite(async (tx) => {
|
||||
@ -145,10 +162,16 @@ export async function processDepositGroup(
|
||||
if (!dg) {
|
||||
return;
|
||||
}
|
||||
dg.depositedPerCoin[i] = true;
|
||||
if (updatedDeposit !== undefined) {
|
||||
dg.depositedPerCoin[i] = updatedDeposit;
|
||||
}
|
||||
if (updatedTxStatus !== undefined) {
|
||||
dg.transactionPerCoin[i] = updatedTxStatus;
|
||||
}
|
||||
await tx.depositGroups.put(dg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await ws.db
|
||||
.mktx((x) => [x.depositGroups])
|
||||
@ -157,13 +180,17 @@ export async function processDepositGroup(
|
||||
if (!dg) {
|
||||
return;
|
||||
}
|
||||
let allDeposited = true;
|
||||
for (const d of depositGroup.depositedPerCoin) {
|
||||
if (!d) {
|
||||
allDeposited = false;
|
||||
let allDepositedAndWired = true;
|
||||
for (let i = 0; i < depositGroup.depositedPerCoin.length; i++) {
|
||||
if (
|
||||
!depositGroup.depositedPerCoin[i] ||
|
||||
depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired
|
||||
) {
|
||||
allDepositedAndWired = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allDeposited) {
|
||||
if (allDepositedAndWired) {
|
||||
dg.timestampFinished = TalerProtocolTimestamp.now();
|
||||
dg.operationStatus = OperationStatus.Finished;
|
||||
await tx.depositGroups.put(dg);
|
||||
@ -172,14 +199,24 @@ export async function processDepositGroup(
|
||||
return OperationAttemptResult.finishedEmpty();
|
||||
}
|
||||
|
||||
function txStatusFromTrack(t: TrackTransaction): TransactionStatus {
|
||||
if (t.type === "accepted") {
|
||||
if (!t.kyc_ok && t.requirement_row !== undefined) {
|
||||
return TransactionStatus.KycRequired;
|
||||
}
|
||||
return TransactionStatus.Accepted;
|
||||
}
|
||||
if (t.type === "wired") {
|
||||
return TransactionStatus.Wired;
|
||||
}
|
||||
return TransactionStatus.Unknown;
|
||||
}
|
||||
|
||||
export async function trackDepositGroup(
|
||||
ws: InternalWalletState,
|
||||
req: TrackDepositGroupRequest,
|
||||
): Promise<TrackDepositGroupResponse> {
|
||||
const responses: {
|
||||
status: number;
|
||||
body: any;
|
||||
}[] = [];
|
||||
const responses: TrackTransaction[] = [];
|
||||
const depositGroup = await ws.db
|
||||
.mktx((x) => [x.depositGroups])
|
||||
.runReadOnly(async (tx) => {
|
||||
@ -200,9 +237,21 @@ export async function trackDepositGroup(
|
||||
contractData,
|
||||
);
|
||||
|
||||
for (const dp of depositPermissions) {
|
||||
const track = await trackDepositPermission(ws, depositGroup, dp);
|
||||
responses.push(track);
|
||||
}
|
||||
|
||||
return { responses };
|
||||
}
|
||||
|
||||
async function trackDepositPermission(
|
||||
ws: InternalWalletState,
|
||||
depositGroup: DepositGroupRecord,
|
||||
dp: CoinDepositPermission,
|
||||
): Promise<TrackTransaction> {
|
||||
const wireHash = depositGroup.contractTermsRaw.h_wire;
|
||||
|
||||
for (const dp of depositPermissions) {
|
||||
const url = new URL(
|
||||
`deposits/${wireHash}/${depositGroup.merchantPub}/${depositGroup.contractTermsHash}/${dp.coin_pub}`,
|
||||
dp.exchange_url,
|
||||
@ -216,15 +265,27 @@ export async function trackDepositGroup(
|
||||
});
|
||||
url.searchParams.set("merchant_sig", sigResp.sig);
|
||||
const httpResp = await ws.http.get(url.href);
|
||||
const body = await httpResp.json();
|
||||
responses.push({
|
||||
body,
|
||||
status: httpResp.status,
|
||||
});
|
||||
switch (httpResp.status) {
|
||||
case HttpStatusCode.Accepted: {
|
||||
const accepted = await readSuccessResponseJsonOrThrow(
|
||||
httpResp,
|
||||
codecForTackTransactionAccepted(),
|
||||
);
|
||||
return { type: "accepted", ...accepted };
|
||||
}
|
||||
case HttpStatusCode.Ok: {
|
||||
const wired = await readSuccessResponseJsonOrThrow(
|
||||
httpResp,
|
||||
codecForTackTransactionWired(),
|
||||
);
|
||||
return { type: "wired", ...wired };
|
||||
}
|
||||
default: {
|
||||
throw Error(
|
||||
`unexpected response from track-transaction (${httpResp.status})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
responses,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getFeeForDeposit(
|
||||
@ -491,6 +552,9 @@ export async function createDepositGroup(
|
||||
noncePub: noncePair.pub,
|
||||
timestampCreated: AbsoluteTime.toTimestamp(now),
|
||||
timestampFinished: undefined,
|
||||
transactionPerCoin: payCoinSel.coinSel.coinPubs.map(
|
||||
() => TransactionStatus.Unknown,
|
||||
),
|
||||
payCoinSelection: payCoinSel.coinSel,
|
||||
payCoinSelectionUid: encodeCrock(getRandomBytes(32)),
|
||||
depositedPerCoin: payCoinSel.coinSel.coinPubs.map(() => false),
|
||||
|
@ -53,6 +53,7 @@ import {
|
||||
WalletContractData,
|
||||
PeerPushPaymentInitiationStatus,
|
||||
PeerPullPaymentIncomingStatus,
|
||||
TransactionStatus,
|
||||
} from "../db.js";
|
||||
import { InternalWalletState } from "../internal-wallet-state.js";
|
||||
import { assertUnreachable } from "../util/assertUnreachable.js";
|
||||
@ -552,6 +553,13 @@ function buildTransactionForDeposit(
|
||||
TransactionType.Deposit,
|
||||
dg.depositGroupId,
|
||||
),
|
||||
wireTransferProgress:
|
||||
(100 *
|
||||
dg.transactionPerCoin.reduce(
|
||||
(prev, cur) => prev + (cur === TransactionStatus.Wired ? 1 : 0),
|
||||
0,
|
||||
)) /
|
||||
dg.transactionPerCoin.length,
|
||||
depositGroupId: dg.depositGroupId,
|
||||
...(ort?.lastError ? { error: ort.lastError } : {}),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user