fix: 7740 check max on p2p push

This commit is contained in:
Sebastian 2023-06-28 11:38:01 -03:00
parent ce3c3d7839
commit 28dce57f92
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
4 changed files with 59 additions and 16 deletions

View File

@ -367,6 +367,6 @@ test("taler withdraw exchange URI with amount (stringify)", (t) => {
}); });
t.deepEqual( t.deepEqual(
url, url,
"taler://withdraw-exchange/exchange.demo.taler.net/GJKG23V4ZBHEH45YRK7TWQE8ZTY7JWTY5094TQJSRZN5DSDBX8E0?a=KUDOS%3A19", "taler://withdraw-exchange/exchange.demo.taler.net/JFX1NE38C65A5XT8VSNQXX7R7BBG4GNZ63F5T7Y6859V4J8KBKF0?a=KUDOS%3A19",
); );
}); });

View File

@ -14,15 +14,21 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/ */
import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import {
Amounts,
TalerError,
TalerErrorCode,
TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { isFuture, parse } from "date-fns"; import { isFuture, parse } from "date-fns";
import { useState } from "preact/hooks"; import { useEffect, useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js"; import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js"; import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
import { BackgroundError, WxApiType } from "../../wxApi.js";
export function useComponentState({ export function useComponentState({
amount: amountStr, amount: amountStr,
@ -38,9 +44,7 @@ export function useComponentState({
const [timestamp, setTimestamp] = useState<string | undefined>(); const [timestamp, setTimestamp] = useState<string | undefined>();
const hook = useAsyncAsHook(async () => { const hook = useAsyncAsHook(async () => {
const resp = await api.wallet.call(WalletApiOperation.CheckPeerPushDebit, { const resp = await checkPeerPushDebitAndCheckMax(api, amountStr);
amount: amountStr,
});
return resp; return resp;
}); });
@ -59,12 +63,6 @@ export function useComponentState({
), ),
}; };
} }
// if (hook.hasError) {
// return {
// status: "loading-uri",
// error: hook,
// };
// }
const { amountEffective, amountRaw } = hook.response; const { amountEffective, amountRaw } = hook.response;
const debitAmount = Amounts.parseOrThrow(amountEffective); const debitAmount = Amounts.parseOrThrow(amountEffective);
@ -140,3 +138,40 @@ export function useComponentState({
error: undefined, error: undefined,
}; };
} }
async function checkPeerPushDebitAndCheckMax(
api: WxApiType,
amountState: string,
) {
// FIXME : https://bugs.gnunet.org/view.php?id=7872
try {
return await api.wallet.call(WalletApiOperation.CheckPeerPushDebit, {
amount: amountState,
});
} catch (e) {
if (!(e instanceof BackgroundError)) {
throw e;
}
if (
!e.hasErrorCode(
TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE,
)
) {
throw e;
}
const material = Amounts.parseOrThrow(
e.errorDetail.insufficientBalanceDetails.balanceMaterial,
);
const gap = Amounts.parseOrThrow(
e.errorDetail.insufficientBalanceDetails.feeGapEstimate,
);
const newAmount = Amounts.sub(material, gap).amount;
const amount = Amounts.parseOrThrow(amountState);
if (Amounts.cmp(newAmount, amount) === 0) {
//insufficient balance and the exception didn't give
//a good response that allow us to try again
throw e;
}
return checkPeerPushDebitAndCheckMax(api, Amounts.stringify(newAmount));
}
}

View File

@ -1741,7 +1741,7 @@ function DepositDetails({ amount }: { amount: AmountWithFee }): VNode {
</tr> </tr>
<tr> <tr>
<td> <td>
<i18n.Translate>Total transfer</i18n.Translate> <i18n.Translate>Total</i18n.Translate>
</td> </td>
<td> <td>
<Amount value={amount.total} maxFracSize={amount.maxFrac} /> <Amount value={amount.total} maxFracSize={amount.maxFrac} />

View File

@ -24,9 +24,11 @@
import { import {
AbsoluteTime, AbsoluteTime,
CoreApiResponse, CoreApiResponse,
DetailsMap,
Logger, Logger,
LogLevel, LogLevel,
NotificationType, NotificationType,
TalerError,
TalerErrorCode, TalerErrorCode,
TalerErrorDetail, TalerErrorDetail,
WalletDiagnostics, WalletDiagnostics,
@ -92,13 +94,19 @@ export interface BackgroundApiClient {
): Promise<BackgroundOperations[Op]["response"]>; ): Promise<BackgroundOperations[Op]["response"]>;
} }
export class BackgroundError extends Error { export class BackgroundError<T = any> extends Error {
public errorDetail: TalerErrorDetail; public errorDetail: TalerErrorDetail & T;
constructor(title: string, e: TalerErrorDetail) { constructor(title: string, e: TalerErrorDetail & T) {
super(title); super(title);
this.errorDetail = e; this.errorDetail = e;
} }
hasErrorCode<C extends keyof DetailsMap>(
code: C,
): this is BackgroundError<DetailsMap[C]> {
return this.errorDetail.code === code;
}
} }
/** /**