Skip to content

Conversation

@jpuri
Copy link
Contributor

@jpuri jpuri commented Dec 8, 2025

Description

Dapp swap comparison: adding support for mode different command types.

Changelog

CHANGELOG entry:

Related issues

Fixes: https://github.com/MetaMask/MetaMask-planning/issues/6393

Manual testing steps

NA

Screenshots/Recordings

NA

Pre-merge author checklist

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.

Note

Adds support for parsing multiple sequential swap commands with validation and refactors decoding to map inputs by index while adjusting field precedence for amountMin and token/amount selection.

  • Dapp Swap Command Utils (shared/modules/dapp-swap-comparison/dapp-swap-command-utils.ts):
    • Add validateSwapCommands to require at least one swap and enforce sequential swap commands; invoked in getCommandValues.
    • Refactor getGenericValues to iterate commandBytes and read inputs by index; accept merged {...SwapCommands, ...NonSwapCommands}; remove one-swap restriction.
    • Remove getCommandData helper.
    • Adjust precedence when merging decoded results:
      • Prefer newly decoded amountMin where available.
      • For quotesInput, prefer existing srcTokenAmount/srcTokenAddress and prefer decoded destTokenAddress (fallbacks retained).
    • Update V4/V3/V2 exact-in handlers to use new precedence and minor logic tweaks (use || and cached minimumAmount).
  • Tests (shared/modules/dapp-swap-comparison/dapp-swap-command-utils.test.ts):
    • Add tests validating sequential swap command rules (error on non-sequential; allow sequential/repeated).
    • Add cases covering multiple swap command sequences (e.g., V3 + V4, mixed/repeated commands) asserting correct tokens/amounts.
    • Maintain exact-out as unsupported (tests expect error).

Written by Cursor Bugbot for commit 91f660d. This will update automatically on new commits. Configure here.

@jpuri jpuri added team-confirmations Push issues to confirmations team no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed labels Dec 8, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 8, 2025

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@jpuri jpuri enabled auto-merge December 8, 2025 13:40
@github-actions github-actions bot added the size-M label Dec 8, 2025
data,
V4_BASE_ACTIONS_ABI_DEFINITION,
);
const parsedResult = parseV4ExactIn(result[0]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For srcTokenAddress and srcTokenAmount values from first swap command get precedence for destTokenAddress and destTokenAmount values from last swap command get precedence.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Duplicate swap commands process wrong input data

When there are duplicate swap commands of the same type (e.g., two V3_SWAP_EXACT_OUT '01' commands in sequence like ['04', '00', '01', '01']), the swapCommands array will contain duplicates. The forEach loop iterates over each duplicate, but getCommandData uses findIndex which always returns the index of the first occurrence. This means the second '01' command will incorrectly process inputs[2] again instead of inputs[3], causing wrong token amounts and addresses to be computed for multi-hop swaps with repeated command types.

shared/modules/dapp-swap-comparison/dapp-swap-command-utils.ts#L556-L570

commands.forEach((command) => {
const data = getCommandData(commandBytes, inputs, command);
if (data !== undefined) {
const commandParser: DAPP_SWAP_COMMANDS_PARSER_TYPE | undefined =
parserDefinition.find(
(parser: DAPP_SWAP_COMMANDS_PARSER_TYPE) => parser.value === command,
);
const result = commandParser?.handler(data, decodingResult, chainId);
if (result) {
decodingResult = result;
}
}
});

shared/modules/dapp-swap-comparison/dapp-swap-command-utils.ts#L231-L234

) {
const commandIndex = commandBytes.findIndex(
(commandByte: string) => commandByte === command,
);

Fix in Cursor Fix in Web


Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Duplicate swap commands only process first occurrence's data

When processing duplicate swap commands (e.g., two V3_SWAP_EXACT_IN commands in sequence), the getCommandData function uses findIndex which always returns the index of the first occurrence of that command type. Combined with iterating over filtered commands that preserves duplicates, this means duplicate commands will all process the same input data from the first occurrence, ignoring subsequent commands' actual input data. For example, with commands ['00', '00'], both iterations would use inputs[0] and inputs[1] would never be processed, potentially resulting in incorrect token amounts or addresses.

shared/modules/dapp-swap-comparison/dapp-swap-command-utils.ts#L556-L570

commands.forEach((command) => {
const data = getCommandData(commandBytes, inputs, command);
if (data !== undefined) {
const commandParser: DAPP_SWAP_COMMANDS_PARSER_TYPE | undefined =
parserDefinition.find(
(parser: DAPP_SWAP_COMMANDS_PARSER_TYPE) => parser.value === command,
);
const result = commandParser?.handler(data, decodingResult, chainId);
if (result) {
decodingResult = result;
}
}
});

shared/modules/dapp-swap-comparison/dapp-swap-command-utils.ts#L231-L238

) {
const commandIndex = commandBytes.findIndex(
(commandByte: string) => commandByte === command,
);
if (commandIndex < 0) {
return undefined;
}
return inputs[commandIndex];

Fix in Cursor Fix in Web


@metamaskbot
Copy link
Collaborator

Builds ready [fe93b5f]
UI Startup Metrics (1263 ± 83 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1263109115378313111424
load104287812167010881158
domContentLoaded103587512107010811150
domInteractive22155182239
firstPaint50384122540310411133
backgroundConnect22019925312226245
firstReactRender5031173215983
getState3716125164369
initialActions105113
loadScripts82367299168865926
setupStore1474561526
numNetworkReqs86306629
BrowserifyPower User HomeuiStartup------
load------
domContentLoaded------
domInteractive------
firstPaint------
backgroundConnect------
firstReactRender------
getState------
initialActions------
loadScripts------
setupStore------
numNetworkReqs------
WebpackStandard HomeuiStartup846727110070871993
load65557587463692780
domContentLoaded64956986864686777
domInteractive22164872339
firstPaint21492711145199625
backgroundConnect1163361228
firstReactRender62342594757171
getState24145492945
initialActions104112
loadScripts64756686563684774
setupStore1072331216
numNetworkReqs86306629
WebpackPower User HomeuiStartup14391165184215915541737
load70658893281752870
domContentLoaded70058292180742858
domInteractive25175482548
firstPaint257106848180233708
backgroundConnect75765115075545
firstReactRender46387154754
getState18514567661190270
initialActions102012
loadScripts69758091880740856
setupStore1565581437
numNetworkReqs67581051066101
FirefoxBrowserifyStandard HomeuiStartup12881107186913513811524
load104993113287110811184
domContentLoaded104993013287110811184
domInteractive5533175257397
firstPaint------
backgroundConnect45223013748108
firstReactRender36307373653
getState1072941019
initialActions103012
loadScripts102091412486010531125
setupStore126202201020
numNetworkReqs86255724
BrowserifyPower User HomeuiStartup25691591400957730323245
load1549970247652920532329
domContentLoaded1549963247652920532329
domInteractive7630102913669164
firstPaint------
backgroundConnect151231201202172281
firstReactRender5435107145895
getState1437529145170217
initialActions203123
loadScripts1471952237549819512222
setupStore634109416136239
numNetworkReqs69491271570114
WebpackStandard HomeuiStartup15641347203012616261811
load1267109816518613171396
domContentLoaded1266109816518613171396
domInteractive70284005386172
firstPaint------
backgroundConnect4222127174972
firstReactRender4635103104861
getState167201221433
initialActions103122
loadScripts1241105516288612871372
setupStore186245341450
numNetworkReqs86295825
WebpackPower User HomeuiStartup27601792521463532143438
load18531132436056523282490
domContentLoaded18521132435956523282490
domInteractive12530169626482986
firstPaint------
backgroundConnect148251199196189336
firstReactRender5737120155988
getState1408326046174233
initialActions2058623
loadScripts17631117326149521922426
setupStore454100211733234
numNetworkReqs71581211375102
📊 Page Load Benchmark Results

Current Commit: fe93b5f | Date: 12/8/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±37ms) 🟡 | historical mean value: 1.03s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 726ms (±35ms) 🟢 | historical mean value: 718ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 76ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 37ms 1.01s 1.32s 1.07s 1.32s
domContentLoaded 726ms 35ms 705ms 985ms 749ms 985ms
firstPaint 77ms 11ms 64ms 180ms 84ms 180ms
firstContentfulPaint 77ms 11ms 64ms 180ms 84ms 180ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 726 Bytes (0.01%)

@metamaskbot
Copy link
Collaborator

Builds ready [42e6f84]
UI Startup Metrics (1251 ± 101 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12511025153110113101454
load104185712909010951230
domContentLoaded103485212839010901223
domInteractive22155882240
firstPaint638142129842010481159
backgroundConnect21418727514219239
firstReactRender4629109155676
getState3615120184177
initialActions107113
loadScripts8296561073868811002
setupStore1385061423
numNetworkReqs86307630
BrowserifyPower User HomeuiStartup18761499236412619532057
load1089887152211311901232
domContentLoaded1077883151211311821224
domInteractive2617102102745
firstPaint58682129643010301229
backgroundConnect257196626104236545
firstReactRender42345944450
getState18914630833202260
initialActions102112
loadScripts86868512881149731018
setupStore1594971435
numNetworkReqs68591151467109
WebpackStandard HomeuiStartup82170197557847944
load63656382556675739
domContentLoaded63155981856671736
domInteractive22154772339
firstPaint21080798137211596
backgroundConnect1155081329
firstReactRender53341923247132
getState2613103133347
initialActions104112
loadScripts62855781656668734
setupStore1052941118
numNetworkReqs86337630
WebpackPower User HomeuiStartup14811161227417415971774
load73958893495835897
domContentLoaded73258392494826889
domInteractive271774102753
firstPaint26494905202242845
backgroundConnect54663211442193
firstReactRender47396644955
getState19214336439201263
initialActions102011
loadScripts72958191993824887
setupStore1574381438
numNetworkReqs68581991667102
FirefoxBrowserifyStandard HomeuiStartup12821090192115113521683
load1054934160411010921315
domContentLoaded1053934160411010921310
domInteractive59322363783134
firstPaint------
backgroundConnect3923255294382
firstReactRender35297863648
getState963131015
initialActions103122
loadScripts102891914629310741236
setupStore952031015
numNetworkReqs86275724
BrowserifyPower User HomeuiStartup25901569332254630203279
load1558940238752821132306
domContentLoaded1557939238752821132306
domInteractive9731106218776159
firstPaint------
backgroundConnect1712611912421811053
firstReactRender5635179175983
getState1398134048163244
initialActions2035323
loadScripts1469922236448520012200
setupStore3653756031162
numNetworkReqs70561231571114
WebpackStandard HomeuiStartup15641341191411416341782
load1271112416008113191414
domContentLoaded1271112416008213191414
domInteractive75293414788152
firstPaint------
backgroundConnect46221552549120
firstReactRender47369995160
getState1377781426
initialActions103122
loadScripts1245110615798012901385
setupStore157117161355
numNetworkReqs86275725
WebpackPower User HomeuiStartup27751782372754131953412
load18471173273449522722546
domContentLoaded18461172273349522712545
domInteractive11629104822978979
firstPaint------
backgroundConnect159271237228164972
firstReactRender533598115677
getState1428229850176254
initialActions206123
loadScripts17431141271346621842377
setupStore59499112348282
numNetworkReqs71571241477103
📊 Page Load Benchmark Results

Current Commit: 42e6f84 | Date: 12/8/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±38ms) 🟡 | historical mean value: 1.03s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 723ms (±36ms) 🟢 | historical mean value: 718ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±9ms) 🟢 | historical mean value: 76ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 38ms 1.01s 1.31s 1.07s 1.31s
domContentLoaded 723ms 36ms 703ms 991ms 753ms 991ms
firstPaint 76ms 9ms 60ms 148ms 84ms 148ms
firstContentfulPaint 76ms 9ms 60ms 148ms 84ms 148ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 0 Bytes (0%)
  • common: 453 Bytes (0%)

@metamaskbot
Copy link
Collaborator

Builds ready [9472034]
UI Startup Metrics (1257 ± 79 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1257104114847913071380
load102787911376110701119
domContentLoaded102187411286110641111
domInteractive21154472138
firstPaint55693113841010391125
backgroundConnect21919826211226237
firstReactRender443099124969
getState3715156194176
initialActions103112
loadScripts80866691159848898
setupStore137128131327
numNetworkReqs86327630
BrowserifyPower User HomeuiStartup18461625277615119232077
load1049869145610011291190
domContentLoaded1038864143410011221177
domInteractive2817167172848
firstPaint52885145843110321192
backgroundConnect263202575106240528
firstReactRender43346774563
getState18914368158200270
initialActions103112
loadScripts8286651177100913975
setupStore14103341525
numNetworkReqs69592051767105
WebpackStandard HomeuiStartup828715105959850980
load64856985460685759
domContentLoaded64356584660680755
domInteractive21154272239
firstPaint22587852169198664
backgroundConnect1164271129
firstReactRender53331613347129
getState241462102945
initialActions102112
loadScripts64156384460678753
setupStore1073041218
numNetworkReqs86306626
WebpackPower User HomeuiStartup14221104177115815441692
load68454790685750825
domContentLoaded67754189284743815
domInteractive23165792347
firstPaint28684903207242733
backgroundConnect66653112682505
firstReactRender45378564753
getState20213962682222276
initialActions102111
loadScripts67553888984741813
setupStore1484291336
numNetworkReqs69572021867104
FirefoxBrowserifyStandard HomeuiStartup13251130175113414081617
load1086959143710011351290
domContentLoaded1085959143710011351290
domInteractive65352283486134
firstPaint------
backgroundConnect43221672747100
firstReactRender393093104159
getState115128121021
initialActions103122
loadScripts105894414189110991223
setupStore136191191126
numNetworkReqs86265723
BrowserifyPower User HomeuiStartup26071622357856830593342
load1615964256952820922324
domContentLoaded1614964256952820912324
domInteractive12627139425871979
firstPaint------
backgroundConnect1751911682261901021
firstReactRender5335108145796
getState1467627846173237
initialActions2040423
loadScripts1515947254849419622229
setupStore444108111434215
numNetworkReqs70391301473103
WebpackStandard HomeuiStartup15331335191010715921712
load1261112515136813011373
domContentLoaded1261112515136813011373
domInteractive72311814196148
firstPaint------
backgroundConnect4319145214788
firstReactRender42338884455
getState157161151623
initialActions102122
loadScripts1237111014896712801346
setupStore1165161219
numNetworkReqs86275724
WebpackPower User HomeuiStartup28031746442057332013420
load18371115362152922982489
domContentLoaded18361115362152922922489
domInteractive11128118323468982
firstPaint------
backgroundConnect2102412912921921014
firstReactRender59371742161113
getState14882101698172234
initialActions208123
loadScripts17241098251747721772391
setupStore543114613633313
numNetworkReqs70551331470108
📊 Page Load Benchmark Results

Current Commit: 9472034 | Date: 12/8/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±55ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 731ms (±53ms) 🟢 | historical mean value: 724ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 55ms 1.02s 1.38s 1.08s 1.38s
domContentLoaded 731ms 53ms 702ms 1.05s 765ms 1.05s
firstPaint 77ms 11ms 60ms 168ms 88ms 168ms
firstContentfulPaint 77ms 11ms 60ms 168ms 88ms 168ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: -919 Bytes (-0.02%)
  • ui: 126.73 KiB (1.64%)
  • common: 2.16 KiB (0.02%)

@metamaskbot
Copy link
Collaborator

Builds ready [91f660d]
UI Startup Metrics (1351 ± 116 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13511097169411614141611
load1101897143210311461316
domContentLoaded1095894141910311411306
domInteractive25165482745
firstPaint54484143043810861231
backgroundConnect22820226714239252
firstReactRender5331142186188
getState3817164194472
initialActions104112
loadScripts8726941216989081083
setupStore1273551323
numNetworkReqs86336626
BrowserifyPower User HomeuiStartup18611621249715319542157
load1055892156711711271253
domContentLoaded1044882153111611181241
domInteractive2717254242653
firstPaint67680131040810481219
backgroundConnect256190641111233562
firstReactRender49396855259
getState19914770159213268
initialActions103112
loadScripts83967713271169121034
setupStore15107181433
numNetworkReqs69581991966111
WebpackStandard HomeuiStartup838718103157874933
load64556776350689740
domContentLoaded64056275750684734
domInteractive21154262238
firstPaint224102740163209658
backgroundConnect1256991329
firstReactRender61332364462159
getState241377103042
initialActions104113
loadScripts63755975550682732
setupStore1054041218
numNetworkReqs86317629
WebpackPower User HomeuiStartup14771193180614816261737
load74359995490833910
domContentLoaded73659394689820902
domInteractive271785132766
firstPaint301100879226264817
backgroundConnect4175737632166
firstReactRender49428965059
getState19914335548236324
initialActions103011
loadScripts73359194389818899
setupStore1594071437
numNetworkReqs67581131266102
FirefoxBrowserifyStandard HomeuiStartup1342118216339214061506
load108897214037211301202
domContentLoaded108897214027211301202
domInteractive63351652886110
firstPaint------
backgroundConnect4525141225691
firstReactRender41347384260
getState1062641023
initialActions102022
loadScripts106095213406610901185
setupStore126125121122
numNetworkReqs86265724
BrowserifyPower User HomeuiStartup25771559363457630833266
load1626939259253721532293
domContentLoaded1625933259253821522293
domInteractive171311084318911045
firstPaint------
backgroundConnect135241184164170298
firstReactRender5436109145694
getState148741024106175252
initialActions2135523
loadScripts1554923241251520392267
setupStore4743798142254
numNetworkReqs70591211369104
WebpackStandard HomeuiStartup15561336205414116181824
load1249108614308013161388
domContentLoaded1249108614308013151388
domInteractive69262915090153
firstPaint------
backgroundConnect46221662847123
firstReactRender4332104124481
getState197248351566
initialActions102012
loadScripts1223107014008112901369
setupStore166185231349
numNetworkReqs86306725
WebpackPower User HomeuiStartup27581776367455632113443
load18621156276651423332504
domContentLoaded18611155276551423332504
domInteractive3143111844219451046
firstPaint------
backgroundConnect116261033145134304
firstReactRender564097125989
getState146671095111167243
initialActions217123
loadScripts18131107274249722932455
setupStore265283402385
numNetworkReqs71601201473102
📊 Page Load Benchmark Results

Current Commit: 91f660d | Date: 12/9/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±43ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 715ms (±41ms) 🟢 | historical mean value: 734ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±11ms) 🟢 | historical mean value: 79ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 43ms 1.00s 1.36s 1.06s 1.36s
domContentLoaded 715ms 41ms 692ms 1.03s 750ms 1.03s
firstPaint 76ms 11ms 60ms 152ms 88ms 152ms
firstContentfulPaint 76ms 11ms 60ms 152ms 88ms 152ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: -911 Bytes (-0.02%)
  • ui: 25.18 KiB (0.33%)
  • common: 2.07 KiB (0.02%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed size-M team-confirmations Push issues to confirmations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants