@@ -4,7 +4,10 @@ import { useUpdateTransactionPayAmount } from './useUpdateTransactionPayAmount';
44import { simpleSendTransactionControllerMock } from '../../__mocks__/controllers/transaction-controller-mock' ;
55import { transactionApprovalControllerMock } from '../../__mocks__/controllers/approval-controller-mock' ;
66import { otherControllersMock } from '../../__mocks__/controllers/other-controllers-mock' ;
7- import { updateAtomicBatchData } from '../../../../../util/transaction-controller' ;
7+ import {
8+ updateAtomicBatchData ,
9+ updateTransaction ,
10+ } from '../../../../../util/transaction-controller' ;
811import {
912 updateMoneyAccountDepositTokenAmount ,
1013 updateMoneyAccountWithdrawTokenAmount ,
@@ -15,11 +18,15 @@ import {
1518} from '@metamask/transaction-controller' ;
1619import { useUpdateTokenAmount } from '../transactions/useUpdateTokenAmount' ;
1720import Logger from '../../../../../util/Logger' ;
21+ import { useTransactionPayRequiredTokens } from './useTransactionPayData' ;
22+ import { TransactionPayRequiredToken } from '@metamask/transaction-pay-controller' ;
23+ import { Hex } from '@metamask/utils' ;
1824
1925jest . mock ( '../../../../../util/transaction-controller' ) ;
2026jest . mock ( '../../../../UI/Money/utils/moneyAccountTransactions' ) ;
2127jest . mock ( '../transactions/useUpdateTokenAmount' ) ;
2228jest . mock ( '../../../../../util/Logger' ) ;
29+ jest . mock ( './useTransactionPayData' ) ;
2330
2431const moneyAccountDepositMeta : Partial < TransactionMeta > = {
2532 type : TransactionType . moneyAccountDeposit ,
@@ -57,13 +64,17 @@ function runHook({
5764
5865describe ( 'useUpdateTransactionPayAmount' , ( ) => {
5966 const updateAtomicBatchDataMock = jest . mocked ( updateAtomicBatchData ) ;
67+ const updateTransactionMock = jest . mocked ( updateTransaction ) ;
6068 const updateMoneyAccountDepositTokenAmountMock = jest . mocked (
6169 updateMoneyAccountDepositTokenAmount ,
6270 ) ;
6371 const updateMoneyAccountWithdrawTokenAmountMock = jest . mocked (
6472 updateMoneyAccountWithdrawTokenAmount ,
6573 ) ;
6674 const useUpdateTokenAmountMock = jest . mocked ( useUpdateTokenAmount ) ;
75+ const useTransactionPayRequiredTokensMock = jest . mocked (
76+ useTransactionPayRequiredTokens ,
77+ ) ;
6778 const updateTokenAmountMock = jest . fn ( ) ;
6879 const loggerErrorMock = jest . mocked ( Logger . error ) ;
6980
@@ -73,6 +84,7 @@ describe('useUpdateTransactionPayAmount', () => {
7384 useUpdateTokenAmountMock . mockReturnValue ( {
7485 updateTokenAmount : updateTokenAmountMock ,
7586 } ) ;
87+ useTransactionPayRequiredTokensMock . mockReturnValue ( [ ] ) ;
7688 } ) ;
7789
7890 async function flushPromises ( ) {
@@ -259,4 +271,152 @@ describe('useUpdateTransactionPayAmount', () => {
259271 expect . stringContaining ( 'Failed to prepare Money Account withdraw' ) ,
260272 ) ;
261273 } ) ;
274+
275+ describe ( 'syncMoneyAccountDepositRequiredAssets' , ( ) => {
276+ const TOKEN_ADDRESS_MOCK = '0xToken' as Hex ;
277+ const existingRequiredAsset = {
278+ address : TOKEN_ADDRESS_MOCK ,
279+ amount : '0x0' as Hex ,
280+ standard : 'erc20' ,
281+ } ;
282+ const moneyAccountDepositMetaWithRequiredAssets = {
283+ ...moneyAccountDepositMeta ,
284+ requiredAssets : [ existingRequiredAsset ] ,
285+ } ;
286+
287+ beforeEach ( ( ) => {
288+ updateMoneyAccountDepositTokenAmountMock . mockResolvedValue ( [ ] ) ;
289+ useTransactionPayRequiredTokensMock . mockReturnValue ( [
290+ { decimals : 6 } as TransactionPayRequiredToken ,
291+ ] ) ;
292+ } ) ;
293+
294+ it ( 'calls updateTransaction with hex-encoded amount when requiredAssets exist' , async ( ) => {
295+ const { result } = runHook ( {
296+ transactionMeta : moneyAccountDepositMetaWithRequiredAssets ,
297+ } ) ;
298+
299+ result . current . updateTransactionPayAmount ( '1' ) ;
300+
301+ await flushPromises ( ) ;
302+
303+ expect ( updateTransactionMock ) . toHaveBeenCalledTimes ( 1 ) ;
304+ expect ( updateTransactionMock ) . toHaveBeenCalledWith (
305+ expect . objectContaining ( {
306+ requiredAssets : [ { ...existingRequiredAsset , amount : '0xf4240' } ] ,
307+ } ) ,
308+ 'Money Account deposit: sync requiredAssets amount' ,
309+ ) ;
310+ } ) ;
311+
312+ it ( 'rounds fractional atomic amounts up before encoding' , async ( ) => {
313+ const { result } = runHook ( {
314+ transactionMeta : moneyAccountDepositMetaWithRequiredAssets ,
315+ } ) ;
316+
317+ result . current . updateTransactionPayAmount ( '1.0000005' ) ;
318+
319+ await flushPromises ( ) ;
320+
321+ expect ( updateTransactionMock ) . toHaveBeenCalledWith (
322+ expect . objectContaining ( {
323+ requiredAssets : [ { ...existingRequiredAsset , amount : '0xf4241' } ] ,
324+ } ) ,
325+ expect . any ( String ) ,
326+ ) ;
327+ } ) ;
328+
329+ it ( 'does not call updateTransaction when transactionMeta has no requiredAssets' , async ( ) => {
330+ const { result } = runHook ( { transactionMeta : moneyAccountDepositMeta } ) ;
331+
332+ result . current . updateTransactionPayAmount ( '1' ) ;
333+
334+ await flushPromises ( ) ;
335+
336+ expect ( updateTransactionMock ) . not . toHaveBeenCalled ( ) ;
337+ } ) ;
338+
339+ it ( 'does not call updateTransaction when no required tokens are available' , async ( ) => {
340+ useTransactionPayRequiredTokensMock . mockReturnValue ( [ ] ) ;
341+
342+ const { result } = runHook ( {
343+ transactionMeta : moneyAccountDepositMetaWithRequiredAssets ,
344+ } ) ;
345+
346+ result . current . updateTransactionPayAmount ( '1' ) ;
347+
348+ await flushPromises ( ) ;
349+
350+ expect ( updateTransactionMock ) . not . toHaveBeenCalled ( ) ;
351+ } ) ;
352+
353+ it ( 'does not call updateTransaction when computed amount matches existing amount' , async ( ) => {
354+ const { result } = runHook ( {
355+ transactionMeta : {
356+ ...moneyAccountDepositMeta ,
357+ requiredAssets : [ { ...existingRequiredAsset , amount : '0xf4240' } ] ,
358+ } ,
359+ } ) ;
360+
361+ result . current . updateTransactionPayAmount ( '1' ) ;
362+
363+ await flushPromises ( ) ;
364+
365+ expect ( updateTransactionMock ) . not . toHaveBeenCalled ( ) ;
366+ } ) ;
367+
368+ it ( 'does not run sync logic for non-deposit transaction types' , async ( ) => {
369+ updateMoneyAccountWithdrawTokenAmountMock . mockResolvedValue ( [ ] ) ;
370+
371+ const { result } = runHook ( {
372+ transactionMeta : {
373+ ...moneyAccountWithdrawMeta ,
374+ requiredAssets : [ existingRequiredAsset ] ,
375+ } ,
376+ } ) ;
377+
378+ result . current . updateTransactionPayAmount ( '1' ) ;
379+
380+ await flushPromises ( ) ;
381+
382+ expect ( updateTransactionMock ) . not . toHaveBeenCalled ( ) ;
383+ } ) ;
384+
385+ it ( 'logs an error when updateTransaction throws' , async ( ) => {
386+ const error = new Error ( 'updateTransaction failed' ) ;
387+ updateTransactionMock . mockImplementation ( ( ) => {
388+ throw error ;
389+ } ) ;
390+
391+ const { result } = runHook ( {
392+ transactionMeta : moneyAccountDepositMetaWithRequiredAssets ,
393+ } ) ;
394+
395+ result . current . updateTransactionPayAmount ( '1' ) ;
396+
397+ await flushPromises ( ) ;
398+
399+ expect ( loggerErrorMock ) . toHaveBeenCalledWith (
400+ error ,
401+ 'Failed to sync Money Account deposit requiredAssets amount' ,
402+ ) ;
403+ } ) ;
404+
405+ it ( 'still applies money account deposit updates after syncing requiredAssets' , async ( ) => {
406+ updateMoneyAccountDepositTokenAmountMock . mockResolvedValue ( [
407+ { nestedTransactionIndex : 0 , transactionData : '0xaaaa' } ,
408+ ] ) ;
409+
410+ const { result } = runHook ( {
411+ transactionMeta : moneyAccountDepositMetaWithRequiredAssets ,
412+ } ) ;
413+
414+ result . current . updateTransactionPayAmount ( '1' ) ;
415+
416+ await flushPromises ( ) ;
417+
418+ expect ( updateTransactionMock ) . toHaveBeenCalledTimes ( 1 ) ;
419+ expect ( updateAtomicBatchDataMock ) . toHaveBeenCalledTimes ( 1 ) ;
420+ } ) ;
421+ } ) ;
262422} ) ;
0 commit comments