Skip to content

Commit c1c62f9

Browse files
authored
fix(PaymentSession): find minSendAmount independent of rate (#1048)
1 parent e7ca0f0 commit c1c62f9

1 file changed

Lines changed: 33 additions & 42 deletions

File tree

src/background/services/paymentSession.ts

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -84,56 +84,46 @@ export class PaymentSession {
8484
Object.assign(this, this.deps);
8585
}
8686

87-
#adjustAmountLastRate: AmountValue;
88-
#adjustAmountController = new AbortController();
89-
#adjustAmountPromise: null | Promise<void> = null;
90-
adjustAmount(rate: AmountValue): Promise<void> {
91-
if (this.#adjustAmountLastRate && rate !== this.#adjustAmountLastRate) {
92-
this.#adjustAmountController.abort(
93-
new DOMException(
94-
`Aborting existing probing for rate=${this.#adjustAmountLastRate}`,
95-
'AbortError',
96-
),
97-
);
98-
this.#adjustAmountController = new AbortController();
99-
this.#adjustAmountPromise = null;
100-
}
101-
102-
this.#adjustAmountLastRate = rate;
103-
this.#adjustAmountPromise ??= this._adjustAmount(
104-
rate,
105-
this.#adjustAmountController.signal,
106-
);
107-
108-
return this.#adjustAmountPromise;
87+
// We keep setting #minSendAmount to non-zero values as we probe. Instead of
88+
// checking #minSendAmount > 0, use this boolean to know if probing completed.
89+
#minSendAmountFound = false;
90+
#minSendAmount = 0n;
91+
#minSendAmountPromise: ReturnType<typeof this._findMinSendAmount>;
92+
93+
findMinSendAmount(): Promise<void> {
94+
this.#minSendAmountPromise ??= this._findMinSendAmount();
95+
return this.#minSendAmountPromise;
10996
}
11097

111-
private async _adjustAmount(
112-
rate: AmountValue,
113-
signal: AbortSignal,
114-
): Promise<void> {
115-
this.rate = rate;
98+
get minSendAmount(): bigint {
99+
if (!this.#minSendAmountFound) {
100+
throw new Error('minSendAmount not figured out yet');
101+
}
102+
return this.#minSendAmount;
103+
}
116104

105+
async adjustAmount(hourlyRate: AmountValue) {
106+
this.rate = hourlyRate;
117107
// The amount that needs to be sent every second.
118108
// In senders asset scale already.
119-
let amountToSend = BigInt(this.rate) / 3600n;
109+
await this.findMinSendAmount();
110+
if (this.rate !== hourlyRate) {
111+
throw new DOMException(
112+
`Aborting existing probing for rate=${hourlyRate}`,
113+
'AbortError',
114+
);
115+
}
116+
const amount = BigInt(this.rate) / 3600n;
117+
this.setAmount(bigIntMax(amount, this.#minSendAmount));
118+
}
119+
120+
private async _findMinSendAmount(signal?: AbortSignal): Promise<void> {
121+
let amountToSend = bigIntMax(this.#minSendAmount, MIN_SEND_AMOUNT);
120122
const senderAssetScale = this.sender.assetScale;
121123
const receiverAssetScale = this.receiver.assetScale;
122124
const isCrossCurrency = this.sender.assetCode !== this.receiver.assetCode;
123125

124126
if (!isCrossCurrency) {
125-
if (amountToSend <= MIN_SEND_AMOUNT) {
126-
// We need to add another unit when using a debit amount, since
127-
// @interledger/pay subtracts one unit.
128-
if (senderAssetScale <= receiverAssetScale) {
129-
amountToSend = MIN_SEND_AMOUNT + 1n;
130-
} else if (senderAssetScale > receiverAssetScale) {
131-
// If the sender scale is greater than the receiver scale, the unit
132-
// issue will not be present.
133-
amountToSend = MIN_SEND_AMOUNT;
134-
}
135-
}
136-
137127
// If the sender can facilitate the rate, but the amount can not be
138128
// represented in the receiver's scale we need to send the minimum amount
139129
// for the receiver (1 unit, but in the sender's asset scale)
@@ -165,14 +155,15 @@ export class PaymentSession {
165155

166156
amountToSend = BigInt(amountIter.next().value);
167157
while (true) {
168-
signal.throwIfAborted();
158+
signal?.throwIfAborted();
159+
this.#minSendAmount = amountToSend;
169160
try {
170161
await this.createPaymentQuote(
171162
amountToSend.toString(),
172163
this.incomingPaymentUrl,
173164
this.sender,
174165
);
175-
this.setAmount(amountToSend);
166+
this.#minSendAmountFound = true;
176167
break;
177168
} catch (e) {
178169
if (isTokenExpiredError(e)) {

0 commit comments

Comments
 (0)