wallet-core: refresh when aborting payments
This commit is contained in:
parent
5fc0cb7927
commit
143a4fe4ac
@ -47,6 +47,10 @@ export interface FaultInjectionRequestContext {
|
||||
requestHeaders: Record<string, string | string[] | undefined>;
|
||||
requestBody?: Buffer;
|
||||
dropRequest: boolean;
|
||||
// These are only used when the request is dropped
|
||||
substituteResponseBody?: Buffer;
|
||||
substituteResponseStatusCode?: number;
|
||||
substituteResponseHeaders?: Record<string, string | string[] | undefined>;
|
||||
}
|
||||
|
||||
export interface FaultInjectionResponseContext {
|
||||
@ -101,7 +105,18 @@ export class FaultProxy {
|
||||
}
|
||||
|
||||
if (faultReqContext.dropRequest) {
|
||||
res.destroy();
|
||||
if (faultReqContext.substituteResponseStatusCode) {
|
||||
const statusCode = faultReqContext.substituteResponseStatusCode;
|
||||
res.writeHead(
|
||||
statusCode,
|
||||
http.STATUS_CODES[statusCode],
|
||||
faultReqContext.substituteResponseHeaders,
|
||||
);
|
||||
res.write(faultReqContext.substituteResponseBody);
|
||||
res.end();
|
||||
} else {
|
||||
res.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@ import { runAgeRestrictionsMixedMerchantTest } from "./test-age-restrictions-mix
|
||||
import { runWalletCryptoWorkerTest } from "./test-wallet-cryptoworker.js";
|
||||
import { runWithdrawalHighTest } from "./test-withdrawal-high.js";
|
||||
import { runKycTest } from "./test-kyc.js";
|
||||
import { runPaymentAbortTest } from "./test-payment-abort.js";
|
||||
|
||||
/**
|
||||
* Test runner.
|
||||
@ -159,6 +160,7 @@ const allTests: TestMainFunction[] = [
|
||||
runPaymentIdempotencyTest,
|
||||
runPaymentMultipleTest,
|
||||
runPaymentTest,
|
||||
runPaymentAbortTest,
|
||||
runPaymentTransientTest,
|
||||
runPaymentZeroTest,
|
||||
runPayPaidTest,
|
||||
|
@ -49,6 +49,15 @@ import {
|
||||
TransactionIdStr,
|
||||
} from "./wallet-types.js";
|
||||
|
||||
export enum ExtendedStatus {
|
||||
Pending = "pending",
|
||||
Done = "done",
|
||||
Aborting = "aborting",
|
||||
Aborted = "aborted",
|
||||
Failed = "failed",
|
||||
KycRequired = "kyc-required",
|
||||
}
|
||||
|
||||
export interface TransactionsRequest {
|
||||
/**
|
||||
* return only transactions in the given currency
|
||||
@ -80,6 +89,8 @@ export interface TransactionCommon {
|
||||
// main timestamp of the transaction
|
||||
timestamp: TalerProtocolTimestamp;
|
||||
|
||||
extendedStatus: ExtendedStatus;
|
||||
|
||||
// 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
|
||||
|
@ -538,7 +538,7 @@ export interface WalletDiagnostics {
|
||||
|
||||
export interface TalerErrorDetail {
|
||||
code: TalerErrorCode;
|
||||
when: string;
|
||||
when?: string;
|
||||
hint?: string;
|
||||
[x: string]: unknown;
|
||||
}
|
||||
@ -1553,8 +1553,8 @@ export const codecForAcceptTipRequest = (): Codec<AcceptTipRequest> =>
|
||||
.property("walletTipId", codecForString())
|
||||
.build("AcceptTipRequest");
|
||||
|
||||
export interface AbortPayRequest {
|
||||
proposalId: string;
|
||||
export interface AbortTransactionRequest {
|
||||
transactionId: string;
|
||||
|
||||
/**
|
||||
* Move the payment immediately into an aborted state.
|
||||
@ -1563,15 +1563,15 @@ export interface AbortPayRequest {
|
||||
*
|
||||
* Defaults to false.
|
||||
*/
|
||||
cancelImmediately?: boolean;
|
||||
forceImmediateAbort?: boolean;
|
||||
}
|
||||
|
||||
export const codecForAbortPayRequest =
|
||||
(): Codec<AbortPayRequest> =>
|
||||
buildCodecForObject<AbortPayRequest>()
|
||||
.property("proposalId", codecForString())
|
||||
.property("cancelImmediately", codecOptional(codecForBoolean()))
|
||||
.build("AbortPayRequest");
|
||||
export const codecForAbortTransaction =
|
||||
(): Codec<AbortTransactionRequest> =>
|
||||
buildCodecForObject<AbortTransactionRequest>()
|
||||
.property("transactionId", codecForString())
|
||||
.property("forceImmediateAbort", codecOptional(codecForBoolean()))
|
||||
.build("AbortTransactionRequest");
|
||||
|
||||
export interface GetFeeForDepositRequest {
|
||||
depositPaytoUri: string;
|
||||
|
@ -848,6 +848,13 @@ export enum RefreshOperationStatus {
|
||||
FinishedWithError = 51 /* DORMANT_START + 1 */,
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional information about the reason of a refresh.
|
||||
*/
|
||||
export interface RefreshReasonDetails {
|
||||
proposalId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group of refresh operations. The refreshed coins do not
|
||||
* have to belong to the same exchange, but must have the same
|
||||
@ -880,6 +887,11 @@ export interface RefreshGroupRecord {
|
||||
*/
|
||||
reason: RefreshReason;
|
||||
|
||||
/**
|
||||
* Extra information depending on the reason.
|
||||
*/
|
||||
reasonDetails?: RefreshReasonDetails;
|
||||
|
||||
oldCoinPubs: string[];
|
||||
|
||||
// FIXME: Should this go into a separate
|
||||
@ -2006,7 +2018,7 @@ export const WalletStoresV1 = {
|
||||
),
|
||||
},
|
||||
),
|
||||
exchangeSignkeys: describeStore(
|
||||
exchangeSignKeys: describeStore(
|
||||
"exchangeSignKeys",
|
||||
describeContents<ExchangeSignkeysRecord>({
|
||||
keyPath: ["exchangeDetailsRowId", "signkeyPub"],
|
||||
|
@ -89,7 +89,7 @@ export async function exportBackup(
|
||||
x.config,
|
||||
x.exchanges,
|
||||
x.exchangeDetails,
|
||||
x.exchangeSignkeys,
|
||||
x.exchangeSignKeys,
|
||||
x.coins,
|
||||
x.contractTerms,
|
||||
x.denominations,
|
||||
|
@ -675,7 +675,7 @@ export async function updateExchangeFromUrlHandler(
|
||||
x.exchanges,
|
||||
x.exchangeTos,
|
||||
x.exchangeDetails,
|
||||
x.exchangeSignkeys,
|
||||
x.exchangeSignKeys,
|
||||
x.denominations,
|
||||
x.coins,
|
||||
x.refreshGroups,
|
||||
|
@ -125,6 +125,7 @@ import {
|
||||
} from "../util/retries.js";
|
||||
import {
|
||||
makeTransactionId,
|
||||
runOperationWithErrorReporting,
|
||||
spendCoins,
|
||||
storeOperationError,
|
||||
storeOperationPending,
|
||||
@ -1135,9 +1136,9 @@ export function selectForced(
|
||||
|
||||
export type SelectPayCoinsResult =
|
||||
| {
|
||||
type: "failure";
|
||||
insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
|
||||
}
|
||||
type: "failure";
|
||||
insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails;
|
||||
}
|
||||
| { type: "success"; coinSel: PayCoinSelection };
|
||||
|
||||
/**
|
||||
@ -1594,7 +1595,12 @@ export async function runPayForConfirmPay(
|
||||
ws: InternalWalletState,
|
||||
proposalId: string,
|
||||
): Promise<ConfirmPayResult> {
|
||||
const res = await processPurchasePay(ws, proposalId, { forceNow: true });
|
||||
logger.trace("processing proposal for confirmPay");
|
||||
const opId = RetryTags.byPaymentProposalId(proposalId);
|
||||
const res = await runOperationWithErrorReporting(ws, opId, async () => {
|
||||
return await processPurchasePay(ws, proposalId, { forceNow: true });
|
||||
});
|
||||
logger.trace(`processPurchasePay response type ${res.type}`);
|
||||
switch (res.type) {
|
||||
case OperationAttemptResultType.Finished: {
|
||||
const purchase = await ws.db
|
||||
@ -1623,9 +1629,10 @@ export async function runPayForConfirmPay(
|
||||
const numRetry = opRetry?.retryInfo.retryCounter ?? 0;
|
||||
if (
|
||||
res.errorDetail.code ===
|
||||
TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR &&
|
||||
TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR &&
|
||||
numRetry < maxRetry
|
||||
) {
|
||||
logger.trace("hiding transient error from caller");
|
||||
// Pretend the operation is pending instead of reporting
|
||||
// an error, but only up to maxRetry attempts.
|
||||
await storeOperationPending(
|
||||
@ -1638,20 +1645,11 @@ export async function runPayForConfirmPay(
|
||||
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
|
||||
};
|
||||
} else {
|
||||
// FIXME: allocate error code!
|
||||
await storeOperationError(
|
||||
ws,
|
||||
RetryTags.byPaymentProposalId(proposalId),
|
||||
res.errorDetail,
|
||||
);
|
||||
throw Error("payment failed");
|
||||
}
|
||||
}
|
||||
case OperationAttemptResultType.Pending:
|
||||
await storeOperationPending(
|
||||
ws,
|
||||
`${PendingTaskType.Purchase}:${proposalId}`,
|
||||
);
|
||||
logger.trace("reporting pending as confirmPay response");
|
||||
return {
|
||||
type: ConfirmPayResultType.Pending,
|
||||
transactionId: makeTransactionId(TransactionType.Payment, proposalId),
|
||||
@ -1968,29 +1966,12 @@ export async function processPurchasePay(
|
||||
result: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.status >= 400 && resp.status <= 499) {
|
||||
const errDetails = await readUnexpectedResponseDetails(resp);
|
||||
logger.warn(`server returned ${resp.status} response for /pay`);
|
||||
logger.warn(j2s(errDetails));
|
||||
await ws.db
|
||||
.mktx((x) => [x.purchases])
|
||||
.runReadWrite(async (tx) => {
|
||||
const purch = await tx.purchases.get(proposalId);
|
||||
if (!purch) {
|
||||
return;
|
||||
}
|
||||
// FIXME: Should be some "PayPermanentlyFailed" and error info should be stored
|
||||
purch.purchaseStatus = PurchaseStatus.PaymentAbortFinished;
|
||||
await tx.purchases.put(purch);
|
||||
});
|
||||
throw makePendingOperationFailedError(
|
||||
errDetails,
|
||||
TransactionType.Payment,
|
||||
proposalId,
|
||||
);
|
||||
}
|
||||
|
||||
if (resp.status >= 400 && resp.status <= 499) {
|
||||
logger.trace("got generic 4xx from merchant");
|
||||
const err = await readTalerErrorResponse(resp);
|
||||
throwUnexpectedRequestError(resp, err);
|
||||
}
|
||||
|
||||
const merchantResp = await readSuccessResponseJsonOrThrow(
|
||||
@ -2395,16 +2376,18 @@ async function acceptRefunds(
|
||||
}
|
||||
}
|
||||
|
||||
const refreshCoinsPubs = Object.values(refreshCoinsMap);
|
||||
logger.info(`refreshCoinMap ${j2s(refreshCoinsMap)}`);
|
||||
if (refreshCoinsPubs.length > 0) {
|
||||
await createRefreshGroup(
|
||||
ws,
|
||||
tx,
|
||||
Amounts.currencyOf(refreshCoinsPubs[0].amount),
|
||||
refreshCoinsPubs,
|
||||
RefreshReason.Refund,
|
||||
);
|
||||
if (reason === RefundReason.AbortRefund) {
|
||||
const refreshCoinsPubs = Object.values(refreshCoinsMap);
|
||||
logger.info(`refreshCoinMap ${j2s(refreshCoinsMap)}`);
|
||||
if (refreshCoinsPubs.length > 0) {
|
||||
await createRefreshGroup(
|
||||
ws,
|
||||
tx,
|
||||
Amounts.currencyOf(refreshCoinsPubs[0].amount),
|
||||
refreshCoinsPubs,
|
||||
RefreshReason.Refund,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Are we done with querying yet, or do we need to do another round
|
||||
@ -2808,12 +2791,21 @@ export async function processPurchaseQueryRefund(
|
||||
return OperationAttemptResult.finishedEmpty();
|
||||
}
|
||||
|
||||
export async function abortFailedPayWithRefund(
|
||||
export async function abortPay(
|
||||
ws: InternalWalletState,
|
||||
proposalId: string,
|
||||
cancelImmediately?: boolean,
|
||||
): Promise<void> {
|
||||
const opId = RetryTags.byPaymentProposalId(proposalId);
|
||||
await ws.db
|
||||
.mktx((x) => [x.purchases])
|
||||
.mktx((x) => [
|
||||
x.purchases,
|
||||
x.refreshGroups,
|
||||
x.denominations,
|
||||
x.coinAvailability,
|
||||
x.coins,
|
||||
x.operationRetries,
|
||||
])
|
||||
.runReadWrite(async (tx) => {
|
||||
const purchase = await tx.purchases.get(proposalId);
|
||||
if (!purchase) {
|
||||
@ -2828,10 +2820,30 @@ export async function abortFailedPayWithRefund(
|
||||
purchase.purchaseStatus = PurchaseStatus.AbortingWithRefund;
|
||||
}
|
||||
await tx.purchases.put(purchase);
|
||||
await tx.operationRetries.delete(opId);
|
||||
if (purchase.payInfo) {
|
||||
const coinSel = purchase.payInfo.payCoinSelection;
|
||||
const currency = Amounts.currencyOf(purchase.payInfo.totalPayCost);
|
||||
const refreshCoins: CoinRefreshRequest[] = [];
|
||||
for (let i = 0; i < coinSel.coinPubs.length; i++) {
|
||||
refreshCoins.push({
|
||||
amount: coinSel.coinContributions[i],
|
||||
coinPub: coinSel.coinPubs[i],
|
||||
});
|
||||
}
|
||||
await createRefreshGroup(
|
||||
ws,
|
||||
tx,
|
||||
currency,
|
||||
refreshCoins,
|
||||
RefreshReason.AbortPay,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
runOperationWithErrorReporting(ws, opId, async () => {
|
||||
return await processPurchaseQueryRefund(ws, proposalId, {
|
||||
forceNow: true,
|
||||
});
|
||||
processPurchaseQueryRefund(ws, proposalId, {
|
||||
forceNow: true,
|
||||
}).catch((e) => {
|
||||
logger.trace(`error during refund processing after abort pay: ${e}`);
|
||||
});
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
Amounts,
|
||||
constructPayPullUri,
|
||||
constructPayPushUri,
|
||||
ExtendedStatus,
|
||||
Logger,
|
||||
OrderShortInfo,
|
||||
PaymentStatus,
|
||||
@ -66,6 +67,7 @@ import {
|
||||
import { processDepositGroup } from "./deposits.js";
|
||||
import { getExchangeDetails } from "./exchanges.js";
|
||||
import {
|
||||
abortPay,
|
||||
expectProposalDownload,
|
||||
extractContractData,
|
||||
processPurchasePay,
|
||||
@ -352,6 +354,10 @@ function buildTransactionForPushPaymentDebit(
|
||||
summary: contractTerms.summary,
|
||||
},
|
||||
frozen: false,
|
||||
extendedStatus:
|
||||
pi.status != PeerPushPaymentInitiationStatus.PurseCreated
|
||||
? ExtendedStatus.Pending
|
||||
: ExtendedStatus.Done,
|
||||
pending: pi.status != PeerPushPaymentInitiationStatus.PurseCreated,
|
||||
timestamp: pi.timestampCreated,
|
||||
talerUri: constructPayPushUri({
|
||||
@ -377,6 +383,7 @@ function buildTransactionForPullPaymentDebit(
|
||||
exchangeBaseUrl: pi.exchangeBaseUrl,
|
||||
frozen: false,
|
||||
pending: false,
|
||||
extendedStatus: ExtendedStatus.Done,
|
||||
info: {
|
||||
expiration: pi.contractTerms.purse_expiration,
|
||||
summary: pi.contractTerms.summary,
|
||||
@ -401,6 +408,7 @@ function buildTransactionForPullPaymentCredit(
|
||||
amountEffective: Amounts.stringify(wsr.denomsSel.totalCoinValue),
|
||||
amountRaw: Amounts.stringify(wsr.instructedAmount),
|
||||
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||
extendedStatus: ExtendedStatus.Done,
|
||||
pending: !wsr.timestampFinish,
|
||||
timestamp: wsr.timestampStart,
|
||||
info: {
|
||||
@ -435,6 +443,9 @@ function buildTransactionForPushPaymentCredit(
|
||||
expiration: wsr.wgInfo.contractTerms.purse_expiration,
|
||||
summary: wsr.wgInfo.contractTerms.summary,
|
||||
},
|
||||
extendedStatus: wsr.timestampFinish
|
||||
? ExtendedStatus.Done
|
||||
: ExtendedStatus.Pending,
|
||||
pending: !wsr.timestampFinish,
|
||||
timestamp: wsr.timestampStart,
|
||||
transactionId: makeTransactionId(
|
||||
@ -464,6 +475,9 @@ function buildTransactionForBankIntegratedWithdraw(
|
||||
bankConfirmationUrl: wsr.wgInfo.bankInfo.confirmUrl,
|
||||
},
|
||||
exchangeBaseUrl: wsr.exchangeBaseUrl,
|
||||
extendedStatus: wsr.timestampFinish
|
||||
? ExtendedStatus.Done
|
||||
: ExtendedStatus.Pending,
|
||||
pending: !wsr.timestampFinish,
|
||||
timestamp: wsr.timestampStart,
|
||||
transactionId: makeTransactionId(
|
||||
@ -504,6 +518,9 @@ function buildTransactionForManualWithdraw(
|
||||
exchangePaytoUris,
|
||||
},
|
||||
exchangeBaseUrl: withdrawalGroup.exchangeBaseUrl,
|
||||
extendedStatus: withdrawalGroup.timestampFinish
|
||||
? ExtendedStatus.Done
|
||||
: ExtendedStatus.Pending,
|
||||
pending: !withdrawalGroup.timestampFinish,
|
||||
timestamp: withdrawalGroup.timestampStart,
|
||||
transactionId: makeTransactionId(
|
||||
@ -523,6 +540,9 @@ function buildTransactionForDeposit(
|
||||
type: TransactionType.Deposit,
|
||||
amountRaw: Amounts.stringify(dg.effectiveDepositAmount),
|
||||
amountEffective: Amounts.stringify(dg.totalPayCost),
|
||||
extendedStatus: dg.timestampFinished
|
||||
? ExtendedStatus.Done
|
||||
: ExtendedStatus.Pending,
|
||||
pending: !dg.timestampFinished,
|
||||
frozen: false,
|
||||
timestamp: dg.timestampCreated,
|
||||
@ -547,6 +567,9 @@ function buildTransactionForTip(
|
||||
type: TransactionType.Tip,
|
||||
amountEffective: Amounts.stringify(tipRecord.tipAmountEffective),
|
||||
amountRaw: Amounts.stringify(tipRecord.tipAmountRaw),
|
||||
extendedStatus: tipRecord.pickedUpTimestamp
|
||||
? ExtendedStatus.Done
|
||||
: ExtendedStatus.Pending,
|
||||
pending: !tipRecord.pickedUpTimestamp,
|
||||
frozen: false,
|
||||
timestamp: tipRecord.acceptedTimestamp,
|
||||
@ -654,6 +677,7 @@ async function buildTransactionForRefund(
|
||||
purchaseRecord.refundAmountAwaiting === undefined
|
||||
? undefined
|
||||
: Amounts.stringify(purchaseRecord.refundAmountAwaiting),
|
||||
extendedStatus: ExtendedStatus.Done,
|
||||
pending: false,
|
||||
frozen: false,
|
||||
...(ort?.lastError ? { error: ort.lastError } : {}),
|
||||
@ -710,6 +734,33 @@ async function buildTransactionForPurchase(
|
||||
checkDbInvariant(!!timestamp);
|
||||
checkDbInvariant(!!purchaseRecord.payInfo);
|
||||
|
||||
|
||||
let status: ExtendedStatus;
|
||||
switch (purchaseRecord.purchaseStatus) {
|
||||
case PurchaseStatus.AbortingWithRefund:
|
||||
status = ExtendedStatus.Aborting;
|
||||
break;
|
||||
case PurchaseStatus.Paid:
|
||||
case PurchaseStatus.RepurchaseDetected:
|
||||
status = ExtendedStatus.Done;
|
||||
break;
|
||||
case PurchaseStatus.DownloadingProposal:
|
||||
case PurchaseStatus.QueryingRefund:
|
||||
case PurchaseStatus.Proposed:
|
||||
case PurchaseStatus.Paying:
|
||||
status = ExtendedStatus.Pending;
|
||||
break;
|
||||
case PurchaseStatus.ProposalDownloadFailed:
|
||||
status = ExtendedStatus.Failed;
|
||||
break;
|
||||
case PurchaseStatus.PaymentAbortFinished:
|
||||
status = ExtendedStatus.Aborted;
|
||||
break;
|
||||
default:
|
||||
// FIXME: Should we have some unknown status?
|
||||
status = ExtendedStatus.Pending;
|
||||
}
|
||||
|
||||
return {
|
||||
type: TransactionType.Payment,
|
||||
amountRaw: Amounts.stringify(contractData.amount),
|
||||
@ -723,6 +774,7 @@ async function buildTransactionForPurchase(
|
||||
status: purchaseRecord.timestampFirstSuccessfulPay
|
||||
? PaymentStatus.Paid
|
||||
: PaymentStatus.Accepted,
|
||||
extendedStatus: status,
|
||||
pending: purchaseRecord.purchaseStatus === PurchaseStatus.Paying,
|
||||
refunds,
|
||||
timestamp,
|
||||
@ -1163,3 +1215,19 @@ export async function deleteTransaction(
|
||||
throw Error(`can't delete a '${unknownTxType}' transaction`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function abortTransaction(
|
||||
ws: InternalWalletState,
|
||||
transactionId: string,
|
||||
forceImmediateAbort?: boolean,
|
||||
): Promise<void> {
|
||||
const { type, args: rest } = parseId("txn", transactionId);
|
||||
|
||||
if (type === TransactionType.Payment) {
|
||||
const proposalId = rest[0];
|
||||
await abortPay(ws, proposalId, forceImmediateAbort);
|
||||
} else {
|
||||
const unknownTxType: any = type;
|
||||
throw Error(`can't abort a '${unknownTxType}' transaction`);
|
||||
}
|
||||
}
|
||||
|
@ -660,7 +660,6 @@ export class DbAccess<StoreMap> {
|
||||
const storeNames: string[] = [];
|
||||
const accessibleStores: { [x: string]: StoreWithIndexes<any, any, any> } =
|
||||
{};
|
||||
|
||||
for (let i = 0; i < this.db.objectStoreNames.length; i++) {
|
||||
const sn = this.db.objectStoreNames[i];
|
||||
const swi = (this.stores as any)[sn] as StoreWithIndexes<any, any, any>;
|
||||
|
@ -24,7 +24,7 @@
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
AbortPayRequest as AbortPayRequest,
|
||||
AbortTransactionRequest as AbortTransactionRequest,
|
||||
AcceptBankIntegratedWithdrawalRequest,
|
||||
AcceptExchangeTosRequest,
|
||||
AcceptManualWithdrawalRequest,
|
||||
@ -150,7 +150,7 @@ export enum WalletApiOperation {
|
||||
GetExchangeTos = "getExchangeTos",
|
||||
GetExchangeDetailedInfo = "getExchangeDetailedInfo",
|
||||
RetryPendingNow = "retryPendingNow",
|
||||
AbortPay = "abortPay",
|
||||
AbortTransaction = "abortTransaction",
|
||||
ConfirmPay = "confirmPay",
|
||||
DumpCoins = "dumpCoins",
|
||||
SetCoinSuspended = "setCoinSuspended",
|
||||
@ -329,13 +329,13 @@ export type ConfirmPayOp = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Abort a pending payment.
|
||||
* Puts the payment into an "aborting" state
|
||||
* that can be cancelled.
|
||||
* Abort a transaction
|
||||
*
|
||||
* For payment transactions, it puts the payment into an "aborting" state.
|
||||
*/
|
||||
export type AbortPayOp = {
|
||||
op: WalletApiOperation.AbortPay;
|
||||
request: AbortPayRequest;
|
||||
export type AbortTransactionOp = {
|
||||
op: WalletApiOperation.AbortTransaction;
|
||||
request: AbortTransactionRequest;
|
||||
response: EmptyObject;
|
||||
};
|
||||
|
||||
@ -829,7 +829,7 @@ export type WalletOperations = {
|
||||
[WalletApiOperation.GetContractTermsDetails]: GetContractTermsDetailsOp;
|
||||
[WalletApiOperation.WithdrawTestkudos]: WithdrawTestkudosOp;
|
||||
[WalletApiOperation.ConfirmPay]: ConfirmPayOp;
|
||||
[WalletApiOperation.AbortPay]: AbortPayOp;
|
||||
[WalletApiOperation.AbortTransaction]: AbortTransactionOp;
|
||||
[WalletApiOperation.GetBalances]: GetBalancesOp;
|
||||
[WalletApiOperation.GetTransactions]: GetTransactionsOp;
|
||||
[WalletApiOperation.GetTransactionById]: GetTransactionByIdOp;
|
||||
|
@ -25,7 +25,7 @@
|
||||
import {
|
||||
AbsoluteTime,
|
||||
Amounts,
|
||||
codecForAbortPayRequest,
|
||||
codecForAbortTransaction,
|
||||
codecForAcceptBankIntegratedWithdrawalRequest,
|
||||
codecForAcceptExchangeTosRequest,
|
||||
codecForAcceptManualWithdrawalRequet,
|
||||
@ -180,7 +180,7 @@ import {
|
||||
} from "./operations/exchanges.js";
|
||||
import { getMerchantInfo } from "./operations/merchants.js";
|
||||
import {
|
||||
abortFailedPayWithRefund,
|
||||
abortPay as abortPay,
|
||||
applyRefund,
|
||||
applyRefundFromPurchaseId,
|
||||
confirmPay,
|
||||
@ -217,6 +217,7 @@ import {
|
||||
} from "./operations/testing.js";
|
||||
import { acceptTip, prepareTip, processTip } from "./operations/tip.js";
|
||||
import {
|
||||
abortTransaction,
|
||||
deleteTransaction,
|
||||
getTransactionById,
|
||||
getTransactions,
|
||||
@ -1163,9 +1164,9 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
|
||||
const req = codecForConfirmPayRequest().decode(payload);
|
||||
return await confirmPay(ws, req.proposalId, req.sessionId);
|
||||
}
|
||||
case WalletApiOperation.AbortPay: {
|
||||
const req = codecForAbortPayRequest().decode(payload);
|
||||
await abortFailedPayWithRefund(ws, req.proposalId);
|
||||
case WalletApiOperation.AbortTransaction: {
|
||||
const req = codecForAbortTransaction().decode(payload);
|
||||
await abortTransaction(ws, req.transactionId, req.forceImmediateAbort);
|
||||
return {};
|
||||
}
|
||||
case WalletApiOperation.DumpCoins: {
|
||||
|
Loading…
Reference in New Issue
Block a user