Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions test/jest/console-baseline-unit.json
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,10 @@
"ui/pages/confirmations/hooks/transactions/dapp-swap-comparison/useDappSwapComparisonInfo.test.ts": {
"MetaMask: Background connection not initialized": 2
},
"ui/pages/confirmations/hooks/transactions/useTransactionConfirm.test.ts": {
"error: Money Account withdraw: amount encode": 3,
"error: Money Account withdraw: no committed": 1
},
"ui/pages/confirmations/hooks/useConfirmationAlerts.test.ts": {
"MetaMask: Background connection not initialized": 5,
"React: Act warnings (component updates not wrapped)": 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getMockConfirmStateForTransaction } from '../../../../../../test/data/c
import { genUnapprovedContractInteractionConfirmation } from '../../../../../../test/data/confirmations/contract-interaction';
import { renderHookWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers';
import { useTransactionPayPrimaryRequiredToken } from '../../pay/useTransactionPayData';
import { useLastMoneyAccountWithdrawAmount } from '../../transactions/useLastMoneyAccountWithdrawAmount';
import { AlertsName } from '../constants';
import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants';
import { Severity } from '../../../../../helpers/constants/design-system';
Expand All @@ -20,11 +21,15 @@ jest.mock('@metamask/react-data-query', () => ({
useQuery: jest.fn(),
}));
jest.mock('../../pay/useTransactionPayData');
jest.mock('../../transactions/useLastMoneyAccountWithdrawAmount');

const useQueryMock = jest.mocked(useQuery);
const usePrimaryRequiredTokenMock = jest.mocked(
useTransactionPayPrimaryRequiredToken,
);
const useLastMoneyAccountWithdrawAmountMock = jest.mocked(
useLastMoneyAccountWithdrawAmount,
);

const EXPECTED_ALERT = {
field: RowAlertKey.Amount,
Expand Down Expand Up @@ -92,6 +97,7 @@ describe('useInsufficientMoneyAccountBalanceAlert', () => {
typeof useTransactionPayPrimaryRequiredToken
>,
);
useLastMoneyAccountWithdrawAmountMock.mockReturnValue(undefined);
});

it('returns alert when pending amount exceeds available balance', () => {
Expand Down Expand Up @@ -202,4 +208,36 @@ describe('useInsufficientMoneyAccountBalanceAlert', () => {

expect(result.current).toStrictEqual([]);
});

it('returns alert when the live typed amount exceeds the balance', () => {
// Mirrors mobile: the alert reacts to the current input, not just the
// debounced calldata commit.
useLastMoneyAccountWithdrawAmountMock.mockReturnValue('150');

const { result } = runHook();

expect(result.current).toEqual([EXPECTED_ALERT]);
});

it('prefers the live typed amount over the stale required token amount', () => {
// The user reduced the amount below the balance; the committed calldata
// still carries the previous over-balance amount until the debounce
// re-encodes. The alert must clear immediately.
useLastMoneyAccountWithdrawAmountMock.mockReturnValue('50');
usePrimaryRequiredTokenMock.mockReturnValue({
amountHuman: '150',
} as ReturnType<typeof useTransactionPayPrimaryRequiredToken>);

const { result } = runHook();

expect(result.current).toStrictEqual([]);
});

it('prefers pendingAmount over the live typed amount', () => {
useLastMoneyAccountWithdrawAmountMock.mockReturnValue('50');

const { result } = runHook({ pendingAmount: '150' });

expect(result.current).toEqual([EXPECTED_ALERT]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { hasTransactionType } from '../../../../../../shared/lib/transactions.ut
import { MoneyAccountBalanceServiceQueryKeys } from '../../../../../../shared/lib/money/query-keys';
import { useConfirmContext } from '../../../context/confirm';
import { useTransactionPayPrimaryRequiredToken } from '../../pay/useTransactionPayData';
import { useLastMoneyAccountWithdrawAmount } from '../../transactions/useLastMoneyAccountWithdrawAmount';
import { AlertsName } from '../constants';

const MUSD_UNIT = 10 ** MUSD_DECIMALS;
Expand All @@ -35,7 +36,11 @@ const NON_WITHDRAW_QUERY_KEY = 'money-account-withdraw-alert:disabled';
* withdraw info messenger) so this can run in `useConfirmationAlerts` without
* requiring a money-account route messenger.
*
* Mirrors mobile `useInsufficientMoneyAccountBalanceAlert`.
* Mirrors mobile `useInsufficientMoneyAccountBalanceAlert`, including its
* live-input responsiveness: mobile evaluates the pending typed amount, so
* the extension prefers the synchronously-recorded last withdraw amount over
* `primaryRequiredToken.amountHuman`, which lags typing by the debounced
* calldata encode.
*
* @param options
* @param options.pendingAmount - Optional in-progress human mUSD amount.
Expand All @@ -48,6 +53,9 @@ export function useInsufficientMoneyAccountBalanceAlert({
const t = useI18nContext();
const { currentConfirmation } = useConfirmContext<TransactionMeta>();
const primaryRequiredToken = useTransactionPayPrimaryRequiredToken();
const lastWithdrawAmount = useLastMoneyAccountWithdrawAmount(
currentConfirmation?.id ?? '',
);

const isMoneyAccountWithdraw = hasTransactionType(currentConfirmation, [
TransactionType.moneyAccountWithdraw,
Expand All @@ -71,7 +79,11 @@ export function useInsufficientMoneyAccountBalanceAlert({
enabled: false,
});

const amountHuman = pendingAmount ?? primaryRequiredToken?.amountHuman ?? '0';
const amountHuman =
pendingAmount ??
lastWithdrawAmount ??
primaryRequiredToken?.amountHuman ??
'0';

const withdrawableMusd = useMemo(() => {
if (
Expand Down
Loading