Skip to content

Commit b5472e1

Browse files
feat: cp-7.60.0 gas station support for metamask pay deposits (#23033)
## **Description** Support EIP-7702 gas station when depositing with MetaMask Pay. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: [#6150](MetaMask/MetaMask-planning#6150) ## **Manual testing steps** ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds gas fee token awareness to insufficient balance alerts, simplifies available token selection logic, delegates getGasFeeTokens, and upgrades transaction-pay-controller to v10. > > - **Confirmations / Alerts**: > - Consider `fees.isSourceGasFeeToken` in fee/amount calculations and source network checks within `useInsufficientPayTokenBalanceAlert`. > - Add tests covering gas fee token scenarios and adjust mocks accordingly. > - **Utils (`transaction-pay`)**: > - Simplify `getAvailableTokens`: remove "no native gas" disablement and related i18n; return tokens based on balance/selection/required status only. > - Update tests to drop disabled-message case. > - **Engine / Messenger**: > - Delegate `TransactionController:getGasFeeTokens` to the Transaction Pay controller messenger. > - **Dependencies**: > - Bump `@metamask/transaction-pay-controller` to `^10.0.0` (lockfile updated). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5a0d198. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 2b1a33a commit b5472e1

File tree

7 files changed

+87
-57
lines changed

7 files changed

+87
-57
lines changed

app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.test.ts

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
8787
});
8888

8989
it('returns alert if pay token balance is less than required token amount', () => {
90-
useTransactionPayTokenMock.mockReturnValueOnce({
90+
useTransactionPayTokenMock.mockReturnValue({
9191
payToken: {
9292
...PAY_TOKEN_MOCK,
9393
balanceUsd: '1.22',
@@ -111,14 +111,14 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
111111
});
112112

113113
it('ignores required token amount if skipIfBalance', () => {
114-
useTransactionPayRequiredTokensMock.mockReturnValueOnce([
114+
useTransactionPayRequiredTokensMock.mockReturnValue([
115115
{
116116
...REQUIRED_TOKEN_MOCK,
117117
skipIfBalance: true,
118118
},
119119
]);
120120

121-
useTransactionPayTokenMock.mockReturnValueOnce({
121+
useTransactionPayTokenMock.mockReturnValue({
122122
payToken: {
123123
...PAY_TOKEN_MOCK,
124124
balanceUsd: '1.22',
@@ -134,7 +134,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
134134

135135
describe('for fees', () => {
136136
it('returns alert if pay token balance is less than total source amount', () => {
137-
useTransactionPayTokenMock.mockReturnValueOnce({
137+
useTransactionPayTokenMock.mockReturnValue({
138138
payToken: {
139139
...PAY_TOKEN_MOCK,
140140
balanceRaw: '999',
@@ -160,7 +160,7 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
160160
});
161161

162162
it('returns alert if pay token balance is less than source amount plus source network', () => {
163-
useTransactionPayTokenMock.mockReturnValueOnce({
163+
useTransactionPayTokenMock.mockReturnValue({
164164
payToken: {
165165
...PAY_TOKEN_MOCK,
166166
address: NATIVE_TOKEN_MOCK.address as Hex,
@@ -185,11 +185,45 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
185185
},
186186
]);
187187
});
188+
189+
it('returns alert if pay token balance is less than source amount plus source network if gas fee token', () => {
190+
useTransactionPayTokenMock.mockReturnValue({
191+
payToken: {
192+
...PAY_TOKEN_MOCK,
193+
balanceRaw: '1099',
194+
},
195+
setPayToken: jest.fn(),
196+
});
197+
198+
useTransactionPayTotalsMock.mockReturnValue({
199+
...TOTALS_MOCK,
200+
fees: {
201+
...TOTALS_MOCK.fees,
202+
isSourceGasFeeToken: true,
203+
},
204+
});
205+
206+
const { result } = runHook();
207+
208+
expect(result.current).toStrictEqual([
209+
{
210+
key: AlertKeys.InsufficientPayTokenFees,
211+
field: RowAlertKey.Amount,
212+
isBlocking: true,
213+
title: strings('alert_system.insufficient_pay_token_balance.message'),
214+
message: strings(
215+
'alert_system.insufficient_pay_token_balance_fees.message',
216+
{ amount: '$1.11' },
217+
),
218+
severity: Severity.Danger,
219+
},
220+
]);
221+
});
188222
});
189223

190224
describe('for source network fee', () => {
191225
it('returns alert if native balance is less than total source network fee', () => {
192-
useTokenWithBalanceMock.mockReturnValueOnce({
226+
useTokenWithBalanceMock.mockReturnValue({
193227
...NATIVE_TOKEN_MOCK,
194228
balanceRaw: '99',
195229
} as ReturnType<typeof useTokenWithBalance>);
@@ -212,12 +246,12 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
212246
});
213247

214248
it('returns no alert if pay token is native', () => {
215-
useTokenWithBalanceMock.mockReturnValueOnce({
249+
useTokenWithBalanceMock.mockReturnValue({
216250
...NATIVE_TOKEN_MOCK,
217251
balanceRaw: '99',
218252
} as ReturnType<typeof useTokenWithBalance>);
219253

220-
useTransactionPayTokenMock.mockReturnValueOnce({
254+
useTransactionPayTokenMock.mockReturnValue({
221255
payToken: {
222256
...PAY_TOKEN_MOCK,
223257
address: NATIVE_TOKEN_MOCK.address as Hex,
@@ -230,5 +264,33 @@ describe('useInsufficientPayTokenBalanceAlert', () => {
230264

231265
expect(result.current).toStrictEqual([]);
232266
});
267+
268+
it('returns no alert if source network is using gas fee token', () => {
269+
useTokenWithBalanceMock.mockReturnValue({
270+
...NATIVE_TOKEN_MOCK,
271+
balanceRaw: '99',
272+
} as ReturnType<typeof useTokenWithBalance>);
273+
274+
useTransactionPayTotalsMock.mockReturnValue({
275+
...TOTALS_MOCK,
276+
fees: {
277+
...TOTALS_MOCK.fees,
278+
isSourceGasFeeToken: true,
279+
},
280+
sourceAmount: TOTALS_MOCK.sourceAmount,
281+
});
282+
283+
useTransactionPayTokenMock.mockReturnValue({
284+
payToken: {
285+
...PAY_TOKEN_MOCK,
286+
balanceRaw: '1100',
287+
},
288+
setPayToken: jest.fn(),
289+
});
290+
291+
const { result } = runHook();
292+
293+
expect(result.current).toStrictEqual([]);
294+
});
233295
});
234296
});

app/components/Views/confirmations/hooks/alerts/useInsufficientPayTokenBalanceAlert.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export function useInsufficientPayTokenBalanceAlert({
2727
const totals = useTransactionPayTotals();
2828
const formatFiat = useFiatFormatter({ currency: 'usd' });
2929
const isLoading = useIsTransactionPayLoading();
30+
const isSourceGasFeeToken = totals?.fees.isSourceGasFeeToken ?? false;
3031

3132
const sourceChainId = payToken?.chainId ?? '0x0';
3233

@@ -64,20 +65,20 @@ export function useInsufficientPayTokenBalanceAlert({
6465
}
6566

6667
return new BigNumber(totals?.sourceAmount.raw ?? '0').plus(
67-
isPayTokenNative
68+
isPayTokenNative || isSourceGasFeeToken
6869
? new BigNumber(totals?.fees.sourceNetwork.max.raw ?? '0')
6970
: '0',
7071
);
71-
}, [isLoading, isPayTokenNative, totals]);
72+
}, [isLoading, isPayTokenNative, isSourceGasFeeToken, totals]);
7273

7374
const totalSourceAmountUsd = useMemo(
7475
() =>
7576
new BigNumber(totals?.sourceAmount.usd ?? '0').plus(
76-
isPayTokenNative
77+
isPayTokenNative || isSourceGasFeeToken
7778
? new BigNumber(totals?.fees.sourceNetwork.max.usd ?? '0')
7879
: '0',
7980
),
80-
[isPayTokenNative, totals],
81+
[isPayTokenNative, isSourceGasFeeToken, totals],
8182
);
8283

8384
const targetAmountUsd = useMemo(() => {
@@ -104,9 +105,11 @@ export function useInsufficientPayTokenBalanceAlert({
104105
() =>
105106
payToken &&
106107
!isPayTokenNative &&
108+
!isSourceGasFeeToken &&
107109
totalSourceNetworkFeeRaw.isGreaterThan(nativeToken?.balanceRaw ?? '0'),
108110
[
109111
isPayTokenNative,
112+
isSourceGasFeeToken,
110113
nativeToken?.balanceRaw,
111114
payToken,
112115
totalSourceNetworkFeeRaw,

app/components/Views/confirmations/utils/transaction-pay.test.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
TransactionPaymentToken,
2020
} from '@metamask/transaction-pay-controller';
2121
import { Hex } from '@metamask/utils';
22-
import { strings } from '../../../../../locales/i18n';
2322

2423
const CHAIN_ID_MOCK = '0x1';
2524
const TO_MOCK = '0x0987654321098765432109876543210987654321';
@@ -200,25 +199,6 @@ describe('Transaction Pay Utils', () => {
200199
expect(result).toMatchObject([tokenWithZeroBalance]);
201200
});
202201

203-
it('returns disabled token with message if no native gas', async () => {
204-
const nonNativeToken = {
205-
...TOKEN_MOCK,
206-
address: '0x234',
207-
} as AssetType;
208-
209-
const result = getAvailableTokens({
210-
tokens: [nonNativeToken] as AssetType[],
211-
});
212-
213-
expect(result).toMatchObject([
214-
{
215-
...nonNativeToken,
216-
disabled: true,
217-
disabledMessage: strings('pay_with_modal.no_gas'),
218-
},
219-
]);
220-
});
221-
222202
it('does not return token if no balance', async () => {
223203
const tokenWithZeroBalance = {
224204
...TOKEN_MOCK,

app/components/Views/confirmations/utils/transaction-pay.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import {
1111
TransactionPayRequiredToken,
1212
TransactionPaymentToken,
1313
} from '@metamask/transaction-pay-controller';
14-
import { getNativeTokenAddress } from './asset';
15-
import { strings } from '../../../../../locales/i18n';
1614
import { BigNumber } from 'bignumber.js';
1715
import { isTestNet } from '../../../../util/networks';
1816

@@ -126,22 +124,8 @@ export function getAvailableTokens({
126124
payToken?.address.toLowerCase() === token.address.toLowerCase() &&
127125
payToken?.chainId === token.chainId;
128126

129-
const nativeTokenAddress = getNativeTokenAddress(token.chainId as Hex);
130-
131-
const nativeToken = tokens.find(
132-
(t) => t.address === nativeTokenAddress && t.chainId === token.chainId,
133-
);
134-
135-
const disabled = new BigNumber(nativeToken?.balance ?? 0).isZero();
136-
137-
const disabledMessage = disabled
138-
? strings('pay_with_modal.no_gas')
139-
: undefined;
140-
141127
return {
142128
...token,
143-
disabled,
144-
disabledMessage,
145129
isSelected,
146130
};
147131
});

app/core/Engine/messengers/transaction-pay-controller-messenger/transaction-pay-controller-messenger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export function getTransactionPayControllerMessenger(
3535
'TokenListController:getState',
3636
'TokenRatesController:getState',
3737
'TokensController:getState',
38+
'TransactionController:getGasFeeTokens',
3839
'TransactionController:getState',
3940
'TransactionController:updateTransaction',
4041
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@
286286
"@metamask/swaps-controller": "^15.0.0",
287287
"@metamask/token-search-discovery-controller": "^4.0.0",
288288
"@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A62.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch",
289-
"@metamask/transaction-pay-controller": "^9.0.0",
289+
"@metamask/transaction-pay-controller": "^10.0.0",
290290
"@metamask/tron-wallet-snap": "^1.8.0",
291291
"@metamask/utils": "^11.8.1",
292292
"@ngraveio/bc-ur": "^1.1.6",

yarn.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8965,9 +8965,9 @@ __metadata:
89658965
languageName: node
89668966
linkType: hard
89678967

8968-
"@metamask/transaction-pay-controller@npm:^9.0.0":
8969-
version: 9.0.0
8970-
resolution: "@metamask/transaction-pay-controller@npm:9.0.0"
8968+
"@metamask/transaction-pay-controller@npm:^10.0.0":
8969+
version: 10.0.0
8970+
resolution: "@metamask/transaction-pay-controller@npm:10.0.0"
89718971
dependencies:
89728972
"@ethersproject/abi": "npm:^5.7.0"
89738973
"@ethersproject/contracts": "npm:^5.7.0"
@@ -8981,14 +8981,14 @@ __metadata:
89818981
immer: "npm:^9.0.6"
89828982
lodash: "npm:^4.17.21"
89838983
peerDependencies:
8984-
"@metamask/assets-controllers": ^90.0.0
8985-
"@metamask/bridge-controller": ^62.0.0
8986-
"@metamask/bridge-status-controller": ^62.0.0
8984+
"@metamask/assets-controllers": ^91.0.0
8985+
"@metamask/bridge-controller": ^63.0.0
8986+
"@metamask/bridge-status-controller": ^63.0.0
89878987
"@metamask/gas-fee-controller": ^26.0.0
89888988
"@metamask/network-controller": ^26.0.0
89898989
"@metamask/remote-feature-flag-controller": ^2.0.0
89908990
"@metamask/transaction-controller": ^62.0.0
8991-
checksum: 10/f97b313e75b4229d4cf0213449e4505164a3e4cb276e4b01f04347341dcf01fa3e89f21ea5df2def1fd608acddf574c11b517f4d364bf4f82ad59e11922cf2e3
8991+
checksum: 10/596b50c04ee658bd16aefc8000d8cdbe2ac04e82636e9029b828c352377ca1e1af6b3c33f129ea28ba966553f513f42988e6ad50bc4edb99c59a68467fe6a1f6
89928992
languageName: node
89938993
linkType: hard
89948994

@@ -34467,7 +34467,7 @@ __metadata:
3446734467
"@metamask/test-dapp-solana": "npm:^0.3.0"
3446834468
"@metamask/token-search-discovery-controller": "npm:^4.0.0"
3446934469
"@metamask/transaction-controller": "patch:@metamask/transaction-controller@npm%3A62.0.0#~/.yarn/patches/@metamask-transaction-controller-npm-61.0.0-cccac388c7.patch"
34470-
"@metamask/transaction-pay-controller": "npm:^9.0.0"
34470+
"@metamask/transaction-pay-controller": "npm:^10.0.0"
3447134471
"@metamask/tron-wallet-snap": "npm:^1.8.0"
3447234472
"@metamask/utils": "npm:^11.8.1"
3447334473
"@ngraveio/bc-ur": "npm:^1.1.6"

0 commit comments

Comments
 (0)