wallet-core: remove deprecated txid parsing

This commit is contained in:
Florian Dold 2023-05-24 14:09:25 +02:00
parent 4627c0781c
commit f14c7e5f2a
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
6 changed files with 417 additions and 410 deletions

View File

@ -362,42 +362,6 @@ export enum TombstoneTag {
DeletePeerPushCredit = "delete-peer-push-credit",
}
/**
* Create an event ID from the type and the primary key for the event.
*
* @deprecated use constructTransactionIdentifier instead
*/
export function makeTransactionId(
type: TransactionType,
...args: string[]
): string {
return `txn:${type}:${args.map((x) => encodeURIComponent(x)).join(":")}`;
}
export function parseId(
idType: "txn" | "tmb" | "any",
txId: string,
): {
type: TransactionType;
args: string[];
} {
const txnParts = txId.split(":");
if (txnParts.length < 3) {
throw Error("id should have al least 3 parts separated by ':'");
}
const [prefix, typeStr, ...args] = txnParts;
const type = typeStr as TransactionType;
if (idType != "any" && prefix !== idType) {
throw Error(`id should start with ${idType}`);
}
if (args.length === 0) {
throw Error("id should have one or more arguments");
}
return { type, args };
}
/**
* Create an event ID from the type and the primary key for the event.

View File

@ -118,7 +118,6 @@ import {
TaskIdentifiers,
} from "../util/retries.js";
import {
makeTransactionId,
runLongpollAsync,
runOperationWithErrorReporting,
spendCoins,

View File

@ -59,7 +59,7 @@ import {
OperationAttemptResult,
OperationAttemptResultType,
} from "../util/retries.js";
import { makeCoinAvailable, makeTransactionId } from "./common.js";
import { makeCoinAvailable } from "./common.js";
import { updateExchangeFromUrl } from "./exchanges.js";
import {
getCandidateWithdrawalDenoms,

View File

@ -67,7 +67,6 @@ import {
PeerPushPaymentIncomingStatus,
PeerPullPaymentInitiationRecord,
RefundGroupRecord,
ContractTermsRecord,
} from "../db.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { PendingTaskType } from "../pending-types.js";
@ -76,8 +75,6 @@ import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js";
import { constructTaskIdentifier, TaskIdentifiers } from "../util/retries.js";
import {
makeTombstoneId,
makeTransactionId,
parseId,
resetOperationTimeout,
runOperationWithErrorReporting,
TombstoneTag,
@ -164,209 +161,227 @@ export async function getTransactionById(
ws: InternalWalletState,
req: TransactionByIdRequest,
): Promise<Transaction> {
const { type, args: rest } = parseId("txn", req.transactionId);
if (type === TransactionType.Withdrawal) {
const withdrawalGroupId = rest[0];
return await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.exchangeDetails,
x.exchanges,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
const parsedTx = parseTransactionIdentifier(req.transactionId);
if (!withdrawalGroupRecord) throw Error("not found");
if (!parsedTx) {
throw Error("invalid transaction ID");
}
const opId = TaskIdentifiers.forWithdrawal(withdrawalGroupRecord);
const ort = await tx.operationRetries.get(opId);
switch (parsedTx.tag) {
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
return await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.exchangeDetails,
x.exchanges,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
if (
withdrawalGroupRecord.wgInfo.withdrawalType ===
WithdrawalRecordType.BankIntegrated
) {
return buildTransactionForBankIntegratedWithdraw(
if (!withdrawalGroupRecord) throw Error("not found");
const opId = TaskIdentifiers.forWithdrawal(withdrawalGroupRecord);
const ort = await tx.operationRetries.get(opId);
if (
withdrawalGroupRecord.wgInfo.withdrawalType ===
WithdrawalRecordType.BankIntegrated
) {
return buildTransactionForBankIntegratedWithdraw(
withdrawalGroupRecord,
ort,
);
}
const exchangeDetails = await getExchangeDetails(
tx,
withdrawalGroupRecord.exchangeBaseUrl,
);
if (!exchangeDetails) throw Error("not exchange details");
return buildTransactionForManualWithdraw(
withdrawalGroupRecord,
exchangeDetails,
ort,
);
}
const exchangeDetails = await getExchangeDetails(
tx,
withdrawalGroupRecord.exchangeBaseUrl,
);
if (!exchangeDetails) throw Error("not exchange details");
});
}
return buildTransactionForManualWithdraw(
withdrawalGroupRecord,
exchangeDetails,
ort,
);
});
} else if (type === TransactionType.Payment) {
const proposalId = rest[0];
return await ws.db
.mktx((x) => [
x.purchases,
x.tombstones,
x.operationRetries,
x.contractTerms,
])
.runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) throw Error("not found");
const download = await expectProposalDownload(ws, purchase, tx);
const contractData = download.contractData;
const payOpId = TaskIdentifiers.forPay(purchase);
const payRetryRecord = await tx.operationRetries.get(payOpId);
case TransactionType.Payment: {
const proposalId = parsedTx.proposalId;
return await ws.db
.mktx((x) => [
x.purchases,
x.tombstones,
x.operationRetries,
x.contractTerms,
])
.runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (!purchase) throw Error("not found");
const download = await expectProposalDownload(ws, purchase, tx);
const contractData = download.contractData;
const payOpId = TaskIdentifiers.forPay(purchase);
const payRetryRecord = await tx.operationRetries.get(payOpId);
return buildTransactionForPurchase(
purchase,
contractData,
[], // FIXME: Add refunds from refund group records here.
payRetryRecord,
);
});
} else if (type === TransactionType.Refresh) {
const refreshGroupId = rest[0];
throw Error(`no tx for refresh`);
} else if (type === TransactionType.Tip) {
const tipId = rest[0];
return await ws.db
.mktx((x) => [x.tips, x.operationRetries])
.runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId);
if (!tipRecord) throw Error("not found");
return buildTransactionForPurchase(
purchase,
contractData,
[], // FIXME: Add refunds from refund group records here.
payRetryRecord,
);
});
}
const retries = await tx.operationRetries.get(
TaskIdentifiers.forTipPickup(tipRecord),
);
return buildTransactionForTip(tipRecord, retries);
});
} else if (type === TransactionType.Deposit) {
const depositGroupId = rest[0];
return await ws.db
.mktx((x) => [x.depositGroups, x.operationRetries])
.runReadWrite(async (tx) => {
const depositRecord = await tx.depositGroups.get(depositGroupId);
if (!depositRecord) throw Error("not found");
case TransactionType.Refresh: {
// FIXME: We should return info about the refresh here!
throw Error(`no tx for refresh`);
}
const retries = await tx.operationRetries.get(
TaskIdentifiers.forDeposit(depositRecord),
);
return buildTransactionForDeposit(depositRecord, retries);
});
} else if (type === TransactionType.Refund) {
// FIXME!
throw Error("not implemented");
} else if (type === TransactionType.PeerPullDebit) {
const peerPullPaymentIncomingId = rest[0];
return await ws.db
.mktx((x) => [x.peerPullPaymentIncoming])
.runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get(
peerPullPaymentIncomingId,
);
if (!debit) throw Error("not found");
return buildTransactionForPullPaymentDebit(debit);
});
} else if (type === TransactionType.PeerPushDebit) {
const pursePub = rest[0];
return await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.contractTerms])
.runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub);
if (!debit) throw Error("not found");
const ct = await tx.contractTerms.get(debit.contractTermsHash);
checkDbInvariant(!!ct);
return buildTransactionForPushPaymentDebit(debit, ct.contractTermsRaw);
});
} else if (type === TransactionType.PeerPushCredit) {
const peerPushPaymentIncomingId = rest[0];
return await ws.db
.mktx((x) => [
x.peerPushPaymentIncoming,
x.contractTerms,
x.withdrawalGroups,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPushPaymentIncoming.get(
peerPushPaymentIncomingId,
);
if (!pushInc) throw Error("not found");
const ct = await tx.contractTerms.get(pushInc.contractTermsHash);
checkDbInvariant(!!ct);
case TransactionType.Tip: {
const tipId = parsedTx.walletTipId;
return await ws.db
.mktx((x) => [x.tips, x.operationRetries])
.runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId);
if (!tipRecord) throw Error("not found");
let wg: WithdrawalGroupRecord | undefined = undefined;
let wgOrt: OperationRetryRecord | undefined = undefined;
if (pushInc.withdrawalGroupId) {
wg = await tx.withdrawalGroups.get(pushInc.withdrawalGroupId);
if (wg) {
const withdrawalOpId = TaskIdentifiers.forWithdrawal(wg);
wgOrt = await tx.operationRetries.get(withdrawalOpId);
const retries = await tx.operationRetries.get(
TaskIdentifiers.forTipPickup(tipRecord),
);
return buildTransactionForTip(tipRecord, retries);
});
}
case TransactionType.Deposit: {
const depositGroupId = parsedTx.depositGroupId;
return await ws.db
.mktx((x) => [x.depositGroups, x.operationRetries])
.runReadWrite(async (tx) => {
const depositRecord = await tx.depositGroups.get(depositGroupId);
if (!depositRecord) throw Error("not found");
const retries = await tx.operationRetries.get(
TaskIdentifiers.forDeposit(depositRecord),
);
return buildTransactionForDeposit(depositRecord, retries);
});
}
case TransactionType.Refund:
// FIXME!
throw Error("not implemented");
case TransactionType.PeerPullDebit: {
return await ws.db
.mktx((x) => [x.peerPullPaymentIncoming])
.runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get(
parsedTx.peerPullPaymentIncomingId,
);
if (!debit) throw Error("not found");
return buildTransactionForPullPaymentDebit(debit);
});
}
case TransactionType.PeerPushDebit: {
return await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.contractTerms])
.runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(
parsedTx.pursePub,
);
if (!debit) throw Error("not found");
const ct = await tx.contractTerms.get(debit.contractTermsHash);
checkDbInvariant(!!ct);
return buildTransactionForPushPaymentDebit(
debit,
ct.contractTermsRaw,
);
});
}
case TransactionType.PeerPushCredit: {
const peerPushPaymentIncomingId = parsedTx.peerPushPaymentIncomingId;
return await ws.db
.mktx((x) => [
x.peerPushPaymentIncoming,
x.contractTerms,
x.withdrawalGroups,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPushPaymentIncoming.get(
peerPushPaymentIncomingId,
);
if (!pushInc) throw Error("not found");
const ct = await tx.contractTerms.get(pushInc.contractTermsHash);
checkDbInvariant(!!ct);
let wg: WithdrawalGroupRecord | undefined = undefined;
let wgOrt: OperationRetryRecord | undefined = undefined;
if (pushInc.withdrawalGroupId) {
wg = await tx.withdrawalGroups.get(pushInc.withdrawalGroupId);
if (wg) {
const withdrawalOpId = TaskIdentifiers.forWithdrawal(wg);
wgOrt = await tx.operationRetries.get(withdrawalOpId);
}
}
}
const pushIncOpId = TaskIdentifiers.forPeerPushCredit(pushInc);
let pushIncOrt = await tx.operationRetries.get(pushIncOpId);
const pushIncOpId = TaskIdentifiers.forPeerPushCredit(pushInc);
let pushIncOrt = await tx.operationRetries.get(pushIncOpId);
return buildTransactionForPeerPushCredit(
pushInc,
pushIncOrt,
ct.contractTermsRaw,
wg,
wgOrt,
);
});
} else if (type === TransactionType.PeerPullCredit) {
const pursePub = rest[0];
return await ws.db
.mktx((x) => [
x.peerPullPaymentInitiations,
x.contractTerms,
x.withdrawalGroups,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPullPaymentInitiations.get(pursePub);
if (!pushInc) throw Error("not found");
const ct = await tx.contractTerms.get(pushInc.contractTermsHash);
checkDbInvariant(!!ct);
return buildTransactionForPeerPushCredit(
pushInc,
pushIncOrt,
ct.contractTermsRaw,
wg,
wgOrt,
);
});
}
let wg: WithdrawalGroupRecord | undefined = undefined;
let wgOrt: OperationRetryRecord | undefined = undefined;
if (pushInc.withdrawalGroupId) {
wg = await tx.withdrawalGroups.get(pushInc.withdrawalGroupId);
if (wg) {
const withdrawalOpId = TaskIdentifiers.forWithdrawal(wg);
wgOrt = await tx.operationRetries.get(withdrawalOpId);
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
return await ws.db
.mktx((x) => [
x.peerPullPaymentInitiations,
x.contractTerms,
x.withdrawalGroups,
x.operationRetries,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPullPaymentInitiations.get(pursePub);
if (!pushInc) throw Error("not found");
const ct = await tx.contractTerms.get(pushInc.contractTermsHash);
checkDbInvariant(!!ct);
let wg: WithdrawalGroupRecord | undefined = undefined;
let wgOrt: OperationRetryRecord | undefined = undefined;
if (pushInc.withdrawalGroupId) {
wg = await tx.withdrawalGroups.get(pushInc.withdrawalGroupId);
if (wg) {
const withdrawalOpId = TaskIdentifiers.forWithdrawal(wg);
wgOrt = await tx.operationRetries.get(withdrawalOpId);
}
}
}
const pushIncOpId =
TaskIdentifiers.forPeerPullPaymentInitiation(pushInc);
let pushIncOrt = await tx.operationRetries.get(pushIncOpId);
const pushIncOpId =
TaskIdentifiers.forPeerPullPaymentInitiation(pushInc);
let pushIncOrt = await tx.operationRetries.get(pushIncOpId);
return buildTransactionForPeerPullCredit(
pushInc,
pushIncOrt,
ct.contractTermsRaw,
wg,
wgOrt,
);
});
} else {
const unknownTxType: never = type;
throw Error(`can't retrieve a '${unknownTxType}' transaction`);
return buildTransactionForPeerPullCredit(
pushInc,
pushIncOrt,
ct.contractTermsRaw,
wg,
wgOrt,
);
});
}
}
}
// FIXME: Just a marker helper for unknown states until DD37 is fully implemented.
const mkTxStateUnknown = () => ({
major: TransactionMajorState.Unknown,
});
function buildTransactionForPushPaymentDebit(
pi: PeerPushPaymentInitiationRecord,
contractTerms: PeerContractTerms,
@ -1293,7 +1308,13 @@ export function constructTransactionIdentifier(
export function parseTransactionIdentifier(
transactionId: string,
): ParsedTransactionIdentifier | undefined {
const { type, args: rest } = parseId("any", transactionId);
const txnParts = transactionId.split(":");
if (txnParts.length < 3) {
throw Error("id should have al least 3 parts separated by ':'");
}
const [prefix, type, ...rest] = txnParts;
switch (type) {
case TransactionType.Deposit:
@ -1489,25 +1510,92 @@ export async function deleteTransaction(
ws: InternalWalletState,
transactionId: string,
): Promise<void> {
const { type, args: rest } = parseId("txn", transactionId);
const parsedTx = parseTransactionIdentifier(transactionId);
if (type === TransactionType.PeerPushCredit) {
const peerPushPaymentIncomingId = rest[0];
await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.peerPushPaymentIncoming,
x.tombstones,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPushPaymentIncoming.get(
peerPushPaymentIncomingId,
);
if (!pushInc) {
return;
}
if (pushInc.withdrawalGroupId) {
const withdrawalGroupId = pushInc.withdrawalGroupId;
if (!parsedTx) {
throw Error("invalid transaction ID");
}
switch (parsedTx.tag) {
case TransactionType.PeerPushCredit: {
const peerPushPaymentIncomingId = parsedTx.peerPushPaymentIncomingId;
await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.peerPushPaymentIncoming,
x.tombstones,
])
.runReadWrite(async (tx) => {
const pushInc = await tx.peerPushPaymentIncoming.get(
peerPushPaymentIncomingId,
);
if (!pushInc) {
return;
}
if (pushInc.withdrawalGroupId) {
const withdrawalGroupId = pushInc.withdrawalGroupId;
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId);
await tx.tombstones.put({
id:
TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
});
}
}
await tx.peerPushPaymentIncoming.delete(peerPushPaymentIncomingId);
await tx.tombstones.put({
id:
TombstoneTag.DeletePeerPushCredit +
":" +
peerPushPaymentIncomingId,
});
});
return;
}
case TransactionType.PeerPullCredit: {
const pursePub = parsedTx.pursePub;
await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.peerPullPaymentInitiations,
x.tombstones,
])
.runReadWrite(async (tx) => {
const pullIni = await tx.peerPullPaymentInitiations.get(pursePub);
if (!pullIni) {
return;
}
if (pullIni.withdrawalGroupId) {
const withdrawalGroupId = pullIni.withdrawalGroupId;
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId);
await tx.tombstones.put({
id:
TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
});
}
}
await tx.peerPullPaymentInitiations.delete(pursePub);
await tx.tombstones.put({
id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub,
});
});
return;
}
case TransactionType.Withdrawal: {
const withdrawalGroupId = parsedTx.withdrawalGroupId;
await ws.db
.mktx((x) => [x.withdrawalGroups, x.tombstones])
.runReadWrite(async (tx) => {
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
@ -1516,170 +1604,124 @@ export async function deleteTransaction(
await tx.tombstones.put({
id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
});
return;
}
}
await tx.peerPushPaymentIncoming.delete(peerPushPaymentIncomingId);
await tx.tombstones.put({
id:
TombstoneTag.DeletePeerPushCredit + ":" + peerPushPaymentIncomingId,
});
});
} else if (type === TransactionType.PeerPullCredit) {
const pursePub = rest[0];
await ws.db
.mktx((x) => [
x.withdrawalGroups,
x.peerPullPaymentInitiations,
x.tombstones,
])
.runReadWrite(async (tx) => {
const pullIni = await tx.peerPullPaymentInitiations.get(pursePub);
if (!pullIni) {
return;
}
if (pullIni.withdrawalGroupId) {
const withdrawalGroupId = pullIni.withdrawalGroupId;
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId);
return;
}
case TransactionType.Payment: {
const proposalId = parsedTx.proposalId;
await ws.db
.mktx((x) => [x.purchases, x.tombstones])
.runReadWrite(async (tx) => {
let found = false;
const purchase = await tx.purchases.get(proposalId);
if (purchase) {
found = true;
await tx.purchases.delete(proposalId);
}
if (found) {
await tx.tombstones.put({
id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
id: TombstoneTag.DeletePayment + ":" + proposalId,
});
}
}
await tx.peerPullPaymentInitiations.delete(pursePub);
await tx.tombstones.put({
id: TombstoneTag.DeletePeerPullCredit + ":" + pursePub,
});
});
} else if (type === TransactionType.Withdrawal) {
const withdrawalGroupId = rest[0];
await ws.db
.mktx((x) => [x.withdrawalGroups, x.tombstones])
.runReadWrite(async (tx) => {
const withdrawalGroupRecord = await tx.withdrawalGroups.get(
withdrawalGroupId,
);
if (withdrawalGroupRecord) {
await tx.withdrawalGroups.delete(withdrawalGroupId);
await tx.tombstones.put({
id: TombstoneTag.DeleteWithdrawalGroup + ":" + withdrawalGroupId,
});
return;
}
});
} else if (type === TransactionType.Payment) {
const proposalId = rest[0];
await ws.db
.mktx((x) => [x.purchases, x.tombstones])
.runReadWrite(async (tx) => {
let found = false;
const purchase = await tx.purchases.get(proposalId);
if (purchase) {
found = true;
await tx.purchases.delete(proposalId);
}
if (found) {
await tx.tombstones.put({
id: TombstoneTag.DeletePayment + ":" + proposalId,
});
}
});
} else if (type === TransactionType.Refresh) {
const refreshGroupId = rest[0];
await ws.db
.mktx((x) => [x.refreshGroups, x.tombstones])
.runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
if (rg) {
await tx.refreshGroups.delete(refreshGroupId);
await tx.tombstones.put({
id: TombstoneTag.DeleteRefreshGroup + ":" + refreshGroupId,
});
}
});
} else if (type === TransactionType.Tip) {
const tipId = rest[0];
await ws.db
.mktx((x) => [x.tips, x.tombstones])
.runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId);
if (tipRecord) {
await tx.tips.delete(tipId);
await tx.tombstones.put({
id: TombstoneTag.DeleteTip + ":" + tipId,
});
}
});
} else if (type === TransactionType.Deposit) {
const depositGroupId = rest[0];
await ws.db
.mktx((x) => [x.depositGroups, x.tombstones])
.runReadWrite(async (tx) => {
const tipRecord = await tx.depositGroups.get(depositGroupId);
if (tipRecord) {
await tx.depositGroups.delete(depositGroupId);
await tx.tombstones.put({
id: TombstoneTag.DeleteDepositGroup + ":" + depositGroupId,
});
}
});
} else if (type === TransactionType.Refund) {
const proposalId = rest[0];
const executionTimeStr = rest[1];
return;
}
await ws.db
.mktx((x) => [x.purchases, x.tombstones])
.runReadWrite(async (tx) => {
const purchase = await tx.purchases.get(proposalId);
if (purchase) {
// This should just influence the history view,
// but won't delete any actual refund information.
await tx.tombstones.put({
id: makeTombstoneId(
TombstoneTag.DeleteRefund,
proposalId,
executionTimeStr,
),
});
}
});
} else if (type === TransactionType.PeerPullDebit) {
const peerPullPaymentIncomingId = rest[0];
await ws.db
.mktx((x) => [x.peerPullPaymentIncoming, x.tombstones])
.runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get(
peerPullPaymentIncomingId,
);
if (debit) {
await tx.peerPullPaymentIncoming.delete(peerPullPaymentIncomingId);
await tx.tombstones.put({
id: makeTombstoneId(
TombstoneTag.DeletePeerPullDebit,
peerPullPaymentIncomingId,
),
});
}
});
} else if (type === TransactionType.PeerPushDebit) {
const pursePub = rest[0];
await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.tombstones])
.runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub);
if (debit) {
await tx.peerPushPaymentInitiations.delete(pursePub);
await tx.tombstones.put({
id: makeTombstoneId(TombstoneTag.DeletePeerPushDebit, pursePub),
});
}
});
} else {
const unknownTxType: never = type;
throw Error(`can't delete a '${unknownTxType}' transaction`);
case TransactionType.Refresh: {
const refreshGroupId = parsedTx.refreshGroupId;
await ws.db
.mktx((x) => [x.refreshGroups, x.tombstones])
.runReadWrite(async (tx) => {
const rg = await tx.refreshGroups.get(refreshGroupId);
if (rg) {
await tx.refreshGroups.delete(refreshGroupId);
await tx.tombstones.put({
id: TombstoneTag.DeleteRefreshGroup + ":" + refreshGroupId,
});
}
});
return;
}
case TransactionType.Tip: {
const tipId = parsedTx.walletTipId;
await ws.db
.mktx((x) => [x.tips, x.tombstones])
.runReadWrite(async (tx) => {
const tipRecord = await tx.tips.get(tipId);
if (tipRecord) {
await tx.tips.delete(tipId);
await tx.tombstones.put({
id: TombstoneTag.DeleteTip + ":" + tipId,
});
}
});
return;
}
case TransactionType.Deposit: {
const depositGroupId = parsedTx.depositGroupId;
await ws.db
.mktx((x) => [x.depositGroups, x.tombstones])
.runReadWrite(async (tx) => {
const tipRecord = await tx.depositGroups.get(depositGroupId);
if (tipRecord) {
await tx.depositGroups.delete(depositGroupId);
await tx.tombstones.put({
id: TombstoneTag.DeleteDepositGroup + ":" + depositGroupId,
});
}
});
return;
}
case TransactionType.Refund: {
// FIXME: Implement!
return;
}
case TransactionType.PeerPullDebit: {
const peerPullPaymentIncomingId = parsedTx.peerPullPaymentIncomingId;
await ws.db
.mktx((x) => [x.peerPullPaymentIncoming, x.tombstones])
.runReadWrite(async (tx) => {
const debit = await tx.peerPullPaymentIncoming.get(
peerPullPaymentIncomingId,
);
if (debit) {
await tx.peerPullPaymentIncoming.delete(peerPullPaymentIncomingId);
await tx.tombstones.put({
id: makeTombstoneId(
TombstoneTag.DeletePeerPullDebit,
peerPullPaymentIncomingId,
),
});
}
});
return;
}
case TransactionType.PeerPushDebit: {
const pursePub = parsedTx.pursePub;
await ws.db
.mktx((x) => [x.peerPushPaymentInitiations, x.tombstones])
.runReadWrite(async (tx) => {
const debit = await tx.peerPushPaymentInitiations.get(pursePub);
if (debit) {
await tx.peerPushPaymentInitiations.delete(pursePub);
await tx.tombstones.put({
id: makeTombstoneId(TombstoneTag.DeletePeerPushDebit, pursePub),
});
}
});
return;
}
}
}

View File

@ -118,7 +118,6 @@ import {
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION,
} from "../versions.js";
import { makeTransactionId } from "./common.js";
import {
getExchangeDetails,
getExchangePaytoUri,
@ -1456,10 +1455,10 @@ export async function processWithdrawalGroup(
if (numKycRequired > 0) {
if (kycInfo) {
const txId = makeTransactionId(
TransactionType.Withdrawal,
withdrawalGroup.withdrawalGroupId,
);
const txId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId: withdrawalGroup.withdrawalGroupId,
});
await checkWithdrawalKycStatus(
ws,
withdrawalGroup.exchangeBaseUrl,
@ -2050,12 +2049,13 @@ async function processReserveBankStatus(
r.wgInfo.bankInfo.timestampBankConfirmed = now;
r.status = WithdrawalGroupStatus.PendingQueryingStatus;
// FIXME: Notification is deprecated with DD37.
const transactionId = constructTransactionIdentifier({
tag: TransactionType.Withdrawal,
withdrawalGroupId: r.withdrawalGroupId,
});
ws.notify({
type: NotificationType.WithdrawalGroupBankConfirmed,
transactionId: makeTransactionId(
TransactionType.Withdrawal,
r.withdrawalGroupId,
),
transactionId,
});
} else {
logger.info("withdrawal: transfer not yet confirmed by bank");

View File

@ -159,6 +159,7 @@ describe("Withdraw CTA states", () => {
paytoUris: ["payto://"],
tosAccepted: true,
ageRestrictionOptions: [],
numCoins: 42,
},
);
@ -222,6 +223,7 @@ describe("Withdraw CTA states", () => {
paytoUris: ["payto://"],
tosAccepted: false,
ageRestrictionOptions: [],
numCoins: 42,
},
);