diff --git a/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.test.ts b/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.test.ts index 1a3805a05606..1182a79a70b0 100644 --- a/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.test.ts +++ b/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.test.ts @@ -87,7 +87,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => { }); it('returns alert if pay token balance is less than required token amount', () => { - useTransactionPayTokenMock.mockReturnValueOnce({ + useTransactionPayTokenMock.mockReturnValue({ payToken: { ...PAY_TOKEN_MOCK, balanceUsd: '1.22', @@ -111,14 +111,14 @@ describe('useInsufficientPayTokenBalanceAlert', () => { }); it('ignores required token amount if skipIfBalance', () => { - useTransactionPayRequiredTokensMock.mockReturnValueOnce([ + useTransactionPayRequiredTokensMock.mockReturnValue([ { ...REQUIRED_TOKEN_MOCK, skipIfBalance: true, }, ]); - useTransactionPayTokenMock.mockReturnValueOnce({ + useTransactionPayTokenMock.mockReturnValue({ payToken: { ...PAY_TOKEN_MOCK, balanceUsd: '1.22', @@ -134,7 +134,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => { describe('for fees', () => { it('returns alert if pay token balance is less than total source amount', () => { - useTransactionPayTokenMock.mockReturnValueOnce({ + useTransactionPayTokenMock.mockReturnValue({ payToken: { ...PAY_TOKEN_MOCK, balanceRaw: '999', @@ -160,7 +160,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => { }); it('returns alert if pay token balance is less than source amount plus source network', () => { - useTransactionPayTokenMock.mockReturnValueOnce({ + useTransactionPayTokenMock.mockReturnValue({ payToken: { ...PAY_TOKEN_MOCK, address: NATIVE_TOKEN_MOCK.address as Hex, @@ -185,11 +185,45 @@ describe('useInsufficientPayTokenBalanceAlert', () => { }, ]); }); + + it('returns alert if pay token balance is less than source amount plus source network if gas fee token', () => { + useTransactionPayTokenMock.mockReturnValue({ + payToken: { + ...PAY_TOKEN_MOCK, + balanceRaw: '1099', + }, + setPayToken: jest.fn(), + }); + + useTransactionPayTotalsMock.mockReturnValue({ + ...TOTALS_MOCK, + fees: { + ...TOTALS_MOCK.fees, + isSourceGasFeeToken: true, + }, + }); + + const { result } = runHook(); + + expect(result.current).toStrictEqual([ + { + key: AlertKeys.InsufficientPayTokenFees, + field: RowAlertKey.Amount, + isBlocking: true, + title: strings('alert_system.insufficient_pay_token_balance.message'), + message: strings( + 'alert_system.insufficient_pay_token_balance_fees.message', + { amount: '$1.11' }, + ), + severity: Severity.Danger, + }, + ]); + }); }); describe('for source network fee', () => { it('returns alert if native balance is less than total source network fee', () => { - useTokenWithBalanceMock.mockReturnValueOnce({ + useTokenWithBalanceMock.mockReturnValue({ ...NATIVE_TOKEN_MOCK, balanceRaw: '99', } as ReturnType); @@ -212,12 +246,12 @@ describe('useInsufficientPayTokenBalanceAlert', () => { }); it('returns no alert if pay token is native', () => { - useTokenWithBalanceMock.mockReturnValueOnce({ + useTokenWithBalanceMock.mockReturnValue({ ...NATIVE_TOKEN_MOCK, balanceRaw: '99', } as ReturnType); - useTransactionPayTokenMock.mockReturnValueOnce({ + useTransactionPayTokenMock.mockReturnValue({ payToken: { ...PAY_TOKEN_MOCK, address: NATIVE_TOKEN_MOCK.address as Hex, @@ -230,5 +264,33 @@ describe('useInsufficientPayTokenBalanceAlert', () => { expect(result.current).toStrictEqual([]); }); + + it('returns no alert if source network is using gas fee token', () => { + useTokenWithBalanceMock.mockReturnValue({ + ...NATIVE_TOKEN_MOCK, + balanceRaw: '99', + } as ReturnType); + + useTransactionPayTotalsMock.mockReturnValue({ + ...TOTALS_MOCK, + fees: { + ...TOTALS_MOCK.fees, + isSourceGasFeeToken: true, + }, + sourceAmount: TOTALS_MOCK.sourceAmount, + }); + + useTransactionPayTokenMock.mockReturnValue({ + payToken: { + ...PAY_TOKEN_MOCK, + balanceRaw: '1100', + }, + setPayToken: jest.fn(), + }); + + const { result } = runHook(); + + expect(result.current).toStrictEqual([]); + }); }); }); diff --git a/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.ts b/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.ts index e84799dc2e1b..3d5ec92493fa 100644 --- a/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.ts +++ b/app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.ts @@ -27,6 +27,7 @@ export function useInsufficientPayTokenBalanceAlert({ const totals = useTransactionPayTotals(); const formatFiat = useFiatFormatter({ currency: 'usd' }); const isLoading = useIsTransactionPayLoading(); + const isSourceGasFeeToken = totals?.fees.isSourceGasFeeToken ?? false; const sourceChainId = payToken?.chainId ?? '0x0'; @@ -64,20 +65,20 @@ export function useInsufficientPayTokenBalanceAlert({ } return new BigNumber(totals?.sourceAmount.raw ?? '0').plus( - isPayTokenNative + isPayTokenNative || isSourceGasFeeToken ? new BigNumber(totals?.fees.sourceNetwork.max.raw ?? '0') : '0', ); - }, [isLoading, isPayTokenNative, totals]); + }, [isLoading, isPayTokenNative, isSourceGasFeeToken, totals]); const totalSourceAmountUsd = useMemo( () => new BigNumber(totals?.sourceAmount.usd ?? '0').plus( - isPayTokenNative + isPayTokenNative || isSourceGasFeeToken ? new BigNumber(totals?.fees.sourceNetwork.max.usd ?? '0') : '0', ), - [isPayTokenNative, totals], + [isPayTokenNative, isSourceGasFeeToken, totals], ); const targetAmountUsd = useMemo(() => { @@ -104,9 +105,11 @@ export function useInsufficientPayTokenBalanceAlert({ () => payToken && !isPayTokenNative && + !isSourceGasFeeToken && totalSourceNetworkFeeRaw.isGreaterThan(nativeToken?.balanceRaw ?? '0'), [ isPayTokenNative, + isSourceGasFeeToken, nativeToken?.balanceRaw, payToken, totalSourceNetworkFeeRaw, diff --git a/app/components/Views/confirmations/utils/transaction-pay.test.ts b/app/components/Views/confirmations/utils/transaction-pay.test.ts index 63d96df0f707..0585b81bc0ad 100644 --- a/app/components/Views/confirmations/utils/transaction-pay.test.ts +++ b/app/components/Views/confirmations/utils/transaction-pay.test.ts @@ -19,7 +19,6 @@ import { TransactionPaymentToken, } from '@metamask/transaction-pay-controller'; import { Hex } from '@metamask/utils'; -import { strings } from '../../../../../locales/i18n'; const CHAIN_ID_MOCK = '0x1'; const TO_MOCK = '0x0987654321098765432109876543210987654321'; @@ -200,25 +199,6 @@ describe('Transaction Pay Utils', () => { expect(result).toMatchObject([tokenWithZeroBalance]); }); - it('returns disabled token with message if no native gas', async () => { - const nonNativeToken = { - ...TOKEN_MOCK, - address: '0x234', - } as AssetType; - - const result = getAvailableTokens({ - tokens: [nonNativeToken] as AssetType[], - }); - - expect(result).toMatchObject([ - { - ...nonNativeToken, - disabled: true, - disabledMessage: strings('pay_with_modal.no_gas'), - }, - ]); - }); - it('does not return token if no balance', async () => { const tokenWithZeroBalance = { ...TOKEN_MOCK, diff --git a/app/components/Views/confirmations/utils/transaction-pay.ts b/app/components/Views/confirmations/utils/transaction-pay.ts index f590eff7c9ba..1287d9726bc4 100644 --- a/app/components/Views/confirmations/utils/transaction-pay.ts +++ b/app/components/Views/confirmations/utils/transaction-pay.ts @@ -11,8 +11,6 @@ import { TransactionPayRequiredToken, TransactionPaymentToken, } from '@metamask/transaction-pay-controller'; -import { getNativeTokenAddress } from './asset'; -import { strings } from '../../../../../locales/i18n'; import { BigNumber } from 'bignumber.js'; import { isTestNet } from '../../../../util/networks'; @@ -126,22 +124,8 @@ export function getAvailableTokens({ payToken?.address.toLowerCase() === token.address.toLowerCase() && payToken?.chainId === token.chainId; - const nativeTokenAddress = getNativeTokenAddress(token.chainId as Hex); - - const nativeToken = tokens.find( - (t) => t.address === nativeTokenAddress && t.chainId === token.chainId, - ); - - const disabled = new BigNumber(nativeToken?.balance ?? 0).isZero(); - - const disabledMessage = disabled - ? strings('pay_with_modal.no_gas') - : undefined; - return { ...token, - disabled, - disabledMessage, isSelected, }; }); diff --git a/app/core/Engine/messengers/transaction-pay-controller-messenger/transaction-pay-controller-messenger.ts b/app/core/Engine/messengers/transaction-pay-controller-messenger/transaction-pay-controller-messenger.ts index 90064564ec6a..65112dbe6cd0 100644 --- a/app/core/Engine/messengers/transaction-pay-controller-messenger/transaction-pay-controller-messenger.ts +++ b/app/core/Engine/messengers/transaction-pay-controller-messenger/transaction-pay-controller-messenger.ts @@ -35,6 +35,7 @@ export function getTransactionPayControllerMessenger( 'TokenListController:getState', 'TokenRatesController:getState', 'TokensController:getState', + 'TransactionController:getGasFeeTokens', 'TransactionController:getState', 'TransactionController:updateTransaction', ], diff --git a/package.json b/package.json index a8e225944acd..1ecc7c0ba08a 100644 --- a/package.json +++ b/package.json @@ -286,7 +286,7 @@ "@metamask/swaps-controller": "^15.0.0", "@metamask/token-search-discovery-controller": "^4.0.0", "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A62.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch", - "@metamask/transaction-pay-controller": "^9.0.0", + "@metamask/transaction-pay-controller": "^10.0.0", "@metamask/tron-wallet-snap": "^1.9.1", "@metamask/utils": "^11.8.1", "@ngraveio/bc-ur": "^1.1.6", diff --git a/yarn.lock b/yarn.lock index dc40770692ff..6913585bfb85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8947,9 +8947,9 @@ __metadata: languageName: node linkType: hard -"@metamask/transaction-pay-controller@npm:^9.0.0": - version: 9.0.0 - resolution: "@metamask/transaction-pay-controller@npm:9.0.0" +"@metamask/transaction-pay-controller@npm:^10.0.0": + version: 10.0.0 + resolution: "@metamask/transaction-pay-controller@npm:10.0.0" dependencies: "@ethersproject/abi": "npm:^5.7.0" "@ethersproject/contracts": "npm:^5.7.0" @@ -8963,14 +8963,14 @@ __metadata: immer: "npm:^9.0.6" lodash: "npm:^4.17.21" peerDependencies: - "@metamask/assets-controllers": ^90.0.0 - "@metamask/bridge-controller": ^62.0.0 - "@metamask/bridge-status-controller": ^62.0.0 + "@metamask/assets-controllers": ^91.0.0 + "@metamask/bridge-controller": ^63.0.0 + "@metamask/bridge-status-controller": ^63.0.0 "@metamask/gas-fee-controller": ^26.0.0 "@metamask/network-controller": ^26.0.0 "@metamask/remote-feature-flag-controller": ^2.0.0 "@metamask/transaction-controller": ^62.0.0 - checksum: 10/f97b313e75b4229d4cf0213449e4505164a3e4cb276e4b01f04347341dcf01fa3e89f21ea5df2def1fd608acddf574c11b517f4d364bf4f82ad59e11922cf2e3 + checksum: 10/596b50c04ee658bd16aefc8000d8cdbe2ac04e82636e9029b828c352377ca1e1af6b3c33f129ea28ba966553f513f42988e6ad50bc4edb99c59a68467fe6a1f6 languageName: node linkType: hard @@ -34449,7 +34449,7 @@ __metadata: "@metamask/test-dapp-solana": "npm:^0.3.0" "@metamask/token-search-discovery-controller": "npm:^4.0.0" "@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A62.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch" - "@metamask/transaction-pay-controller": "npm:^9.0.0" + "@metamask/transaction-pay-controller": "npm:^10.0.0" "@metamask/tron-wallet-snap": "npm:^1.9.1" "@metamask/utils": "npm:^11.8.1" "@ngraveio/bc-ur": "npm:^1.1.6"