Skip to content

Commit

Permalink
fix(background)!: better payment confirmation message
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi committed Nov 1, 2024
1 parent 8b3c33f commit c9ddb61
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 4 deletions.
7 changes: 7 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
"pay_error_notEnoughFunds": {
"message": "Insufficient funds to complete the payment."
},
"pay_error_outgoingPaymentFailed": {
"message": "Payment failed."
},
"pay_error_outgoingPaymentCompletionLimitReached": {
"message": "Payment not finished yet.",
"description": "We were polling for completion, but it's not finished yet"
},
"pay_error_invalidReceivers": {
"message": "At the moment, you cannot pay this website.",
"description": "We cannot send money (probable cause: un-peered wallets)"
Expand Down
25 changes: 23 additions & 2 deletions src/background/services/monetization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,38 @@ export class MonetizationService {

const splitAmount = Number(amount) / payableSessions.length;
// TODO: handle paying across two grants (when one grant doesn't have enough funds)
const results = await Promise.allSettled(
let results = await Promise.allSettled(
payableSessions.map((session) => session.pay(splitAmount)),
);
const signal = AbortSignal.timeout(8_000); // can use other signals as well, such as popup closed etc.
results = await Promise.allSettled(
results.map((e) => {
if (e.status !== 'fulfilled') throw e.reason;
if (!e.value) return e.value;
const outgoingPaymentId = e.value.id;
return this.openPaymentsService.outgoingPaymentWaitForCompletion(
outgoingPaymentId,
{ signal, maxAttempts: 10 },
);
}),
);

const totalSentAmount = results
.filter((e) => e.status === 'fulfilled')
.reduce((acc, curr) => acc + BigInt(curr.value?.value ?? 0), 0n);
.reduce(
(acc, curr) => acc + BigInt(curr.value?.debitAmount?.value ?? 0),
0n,
);
if (totalSentAmount === 0n) {
const isNotEnoughFunds = results
.filter((e) => e.status === 'rejected')
.some((e) => isOutOfBalanceError(e.reason));
// TODO: If sentAmount is zero in all outgoing payments, and
// pay_error_outgoingPaymentCompletionLimitReached, it also likely means
// we don't have enough funds.
//
// TODO: If sentAmount is non-zero but not equal to debitAmount, show
// warning that not entire payment went through (yet?)
if (isNotEnoughFunds) {
throw new Error(this.t('pay_error_notEnoughFunds'));
}
Expand Down
40 changes: 39 additions & 1 deletion src/background/services/openPayments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
errorWithKeyToJSON,
getWalletInformation,
isErrorWithKey,
sleep,
withResolvers,
type ErrorWithKeyLike,
} from '@/shared/helpers';
Expand Down Expand Up @@ -694,7 +695,7 @@ export class OpenPaymentsService {
},
{
type: 'outgoing-payment',
actions: ['create'],
actions: ['create', 'read'],
identifier: walletAddress.id,
limits: {
debitAmount: {
Expand Down Expand Up @@ -881,6 +882,43 @@ export class OpenPaymentsService {
return outgoingPayment;
}

async outgoingPaymentWaitForCompletion(
outgoingPaymentId: OutgoingPayment['id'],
{
signal,
maxAttempts = 10,
}: Partial<{ signal: AbortSignal; maxAttempts: number }> = {},
) {
let attempt = 0;
let outgoingPayment: undefined | OutgoingPayment;
while (++attempt <= maxAttempts) {
signal?.throwIfAborted();
try {
outgoingPayment = await this.client!.outgoingPayment.get({
url: outgoingPaymentId,
accessToken: this.token.value,
});
if (outgoingPayment.failed) {
throw new ErrorWithKey('pay_error_outgoingPaymentFailed');
}
if (
outgoingPayment.debitAmount.value === outgoingPayment.sentAmount.value
) {
return outgoingPayment;
}
signal?.throwIfAborted();
await sleep(1500);
} catch (error) {
if (isTokenExpiredError(error)) {
await this.rotateToken();
} else {
throw error;
}
}
}
throw new ErrorWithKey('pay_error_outgoingPaymentCompletionLimitReached');
}

async probeDebitAmount(
amount: AmountValue,
incomingPayment: IncomingPayment['id'],
Expand Down
2 changes: 1 addition & 1 deletion src/background/services/paymentSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ export class PaymentSession {
}
}

return outgoingPayment?.debitAmount;
return outgoingPayment;
}

private setAmount(amount: bigint): void {
Expand Down

0 comments on commit c9ddb61

Please sign in to comment.