Skip to content

Commit 902d193

Browse files
fix(confirmations): cp-8.0.0 skip initial gas estimate for sponsored money account transactions (#32129)
## **Description** Money Account deposit and withdrawal batches trigger synchronous gas estimation when `addTransactionBatch` is called. On networks where gas is sponsored (e.g. Monad Mainnet), a bug in gas estimation can cause a crash when the RPC unexpectedly returns `null` for the latest block — an error condition we are now handling defensively. This PR passes `skipInitialGasEstimate: true` to deposit and withdrawal batches when `isGasFeeSponsored` is true, deferring gas estimation to the async background path where this error condition is handled safely. Non-sponsored flows are unaffected. ## **Changelog** CHANGELOG entry: Fixed a crash that could occur when initiating Money Account transactions on Monad ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Money Account deposit and withdrawal on a sponsored-gas network Scenario: user initiates a deposit on Monad Mainnet Given the user has a Money Account on Monad Mainnet And Monad Mainnet is selected When user taps Deposit and confirms the transaction Then the batch is submitted without crashing And gas estimation completes in the background Scenario: user initiates a withdrawal on Monad Mainnet Given the user has a Money Account with a mUSD balance on Monad Mainnet When user taps Withdraw and confirms the transaction Then the batch is submitted without crashing Scenario: user initiates a withdrawal on a non-sponsored network Given the user has a Money Account on a non-Monad network When user taps Withdraw and confirms the transaction Then skipInitialGasEstimate is false and gas is estimated synchronously as before ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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. #### Performance checks (if applicable) - [ ] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [ ] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [ ] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example ## **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] > **Medium Risk** > Touches confirmation/transaction submission for Money Account flows; behavior change is gated to sponsored-gas (Monad) chains, with tests updated for withdrawals only. > > **Overview** > **Money Account** deposit and withdrawal now pass **`skipInitialGasEstimate: true`** into `addTransactionBatch` when the vault chain is Monad Mainnet (same condition as **`isGasFeeSponsored`** via `isMonadMainnetChainId`), so synchronous gas estimation is skipped and runs on the async path instead. > > Deposits also set **`isGasFeeSponsored`** on the batch (previously only withdrawals did). Withdrawal tests on Monad assert both sponsored flags; non-Monad withdrawal behavior is unchanged aside from not setting `skipInitialGasEstimate`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 85a41fe. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 8e2efd1 commit 902d193

2 files changed

Lines changed: 14 additions & 8 deletions

File tree

app/components/UI/Money/hooks/useMoneyAccount.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ describe('useMoneyAccountWithdrawal', () => {
476476
expect(mockAddTransactionBatch).toHaveBeenCalledWith(
477477
expect.objectContaining({
478478
isGasFeeSponsored: true,
479+
skipInitialGasEstimate: true,
479480
}),
480481
);
481482
});

app/components/UI/Money/hooks/useMoneyAccount.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export function useMoneyAccountDeposit() {
9292
}
9393

9494
const networkClientId = resolveNetworkClientId(chainIdHex);
95+
const isGasFeeSponsored = isMonadMainnetChainId(chainIdHex);
9596

9697
const batchId = bytesToHex(new Uint8Array(uuidParse(uuidv4())));
9798
depositIntentByBatchId.set(batchId.toLowerCase(), intent);
@@ -120,20 +121,22 @@ export function useMoneyAccountDeposit() {
120121
// so `from` must be the money account and `networkClientId` its chain.
121122
await addTransactionBatch({
122123
batchId,
124+
disableHook: true,
125+
disableSequential: true,
123126
from: primaryMoneyAccount.address as Hex,
127+
isGasFeeSponsored,
128+
isInternal: true,
124129
networkClientId,
125130
origin: ORIGIN_METAMASK,
126-
isInternal: true,
127-
disableHook: true,
128-
disableSequential: true,
129-
transactions: [approveTx, depositTx],
130131
requiredAssets: [
131132
{
132133
address: getMoneyAccountDepositAssetAddress(chainIdHex),
133134
amount: '0x0' as Hex,
134135
standard: 'erc20',
135136
},
136137
],
138+
skipInitialGasEstimate: isGasFeeSponsored,
139+
transactions: [approveTx, depositTx],
137140
});
138141
} catch (error) {
139142
depositIntentByBatchId.delete(batchId.toLowerCase());
@@ -178,6 +181,7 @@ export function useMoneyAccountWithdrawal() {
178181
}
179182

180183
const networkClientId = resolveNetworkClientId(chainIdHex);
184+
const isGasFeeSponsored = isMonadMainnetChainId(chainIdHex);
181185

182186
// Placeholder amount — MM Pay re-encodes both calls via
183187
// `updateMoneyAccountWithdrawTokenAmount` once the user picks an amount.
@@ -199,13 +203,14 @@ export function useMoneyAccountWithdrawal() {
199203

200204
try {
201205
await addTransactionBatch({
206+
disableHook: true,
207+
disableSequential: true,
202208
from: primaryMoneyAccount.address as Hex,
209+
isGasFeeSponsored,
210+
isInternal: true,
203211
networkClientId,
204212
origin: ORIGIN_METAMASK,
205-
isInternal: true,
206-
disableHook: true,
207-
disableSequential: true,
208-
isGasFeeSponsored: isMonadMainnetChainId(chainIdHex),
213+
skipInitialGasEstimate: isGasFeeSponsored,
209214
transactions: [withdrawTx, transferTx],
210215
});
211216
} catch (error) {

0 commit comments

Comments
 (0)