@deeeed/metamask-harness 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/adapters.js +20 -11
  3. package/library/actions/extension/assets/open_details.mjs +30 -0
  4. package/library/actions/extension/assets/set_token_visibility.mjs +5 -0
  5. package/library/actions/extension/perps/open_balance_action.mjs +1 -6
  6. package/library/actions/extension/perps/search_markets.mjs +32 -0
  7. package/library/actions/extension/perps/select_market_filter.mjs +3 -2
  8. package/library/actions/extension/perps/set_market_favorite.mjs +6 -1
  9. package/library/actions/extension/swap_bridge/read_visible_state.mjs +2 -6
  10. package/library/actions/extension/swap_bridge/set_amount.mjs +11 -2
  11. package/library/actions/extension/swap_bridge/submit_transaction.mjs +11 -11
  12. package/library/actions/mobile/assets/import_custom_token.mjs +181 -0
  13. package/library/actions/mobile/assets/open_details.mjs +43 -0
  14. package/library/actions/mobile/assets/read_details.mjs +96 -0
  15. package/library/actions/mobile/assets/set_token_visibility.mjs +302 -0
  16. package/library/actions/mobile/assets/verify_sorting.mjs +104 -0
  17. package/library/actions/mobile/networks/add_custom.mjs +125 -0
  18. package/library/actions/mobile/networks/network-management.mjs +132 -0
  19. package/library/actions/mobile/networks/read_visible_state.mjs +43 -0
  20. package/library/actions/mobile/networks/remove_custom.mjs +100 -0
  21. package/library/actions/mobile/perps/search_markets.mjs +46 -0
  22. package/library/actions/mobile/perps/set_market_favorite.mjs +117 -0
  23. package/library/actions/mobile/platform/native-session-name.mjs +14 -0
  24. package/library/actions/mobile/platform/native-session.mjs +59 -0
  25. package/library/actions/mobile/platform/observe-ui.mjs +9 -1
  26. package/library/actions/mobile/swap_bridge/native-session.mjs +10 -45
  27. package/library/actions/mobile/swap_bridge/select_assets.mjs +15 -1
  28. package/library/actions/mobile/swap_bridge/set_amount.mjs +1 -1
  29. package/library/actions/mobile/swap_bridge/set_max_amount.mjs +55 -0
  30. package/library/actions/mobile/swap_bridge/set_slippage.mjs +96 -0
  31. package/library/actions/mobile/swap_bridge/submit_transaction.mjs +141 -0
  32. package/library/actions/mobile/ui/native-navigation.mjs +75 -23
  33. package/library/actions/mobile/ui/navigate.mjs +13 -2
  34. package/library/actions/mobile/wallet/lock.mjs +14 -0
  35. package/library/actions/mobile/wallet/native-ui.mjs +67 -14
  36. package/library/actions/shared/perps/visible-state.mjs +8 -6
  37. package/library/actions/shared/swap-bridge/visible-state.mjs +15 -0
  38. package/library/manifests/extension.action-manifest.json +43 -2
  39. package/library/manifests/mobile.action-manifest.json +308 -1
  40. package/library/recipes/assets/release-token-details.recipe.json +5 -4
  41. package/library/recipes/assets/release-token-hide-readd.recipe.json +2 -0
  42. package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +90 -0
  43. package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +58 -0
  44. package/library/recipes/perps/release-market-search.recipe.json +8 -4
  45. package/library/recipes/perps/release-watchlist.recipe.json +31 -19
  46. package/library/recipes/swap-bridge/release-custom-slippage.recipe.json +5 -13
  47. package/package.json +1 -1
  48. package/scripts/validate-release-report.mjs +28 -14
  49. /package/library/recipes/{assets → extension/assets}/release-custom-network-token-persistence.recipe.json +0 -0
@@ -407,6 +407,14 @@
407
407
  "symbol": {
408
408
  "type": "string"
409
409
  },
410
+ "mode": {
411
+ "type": "string",
412
+ "enum": [
413
+ "lite",
414
+ "pro"
415
+ ],
416
+ "default": "lite"
417
+ },
410
418
  "url": {
411
419
  "type": "string"
412
420
  },
@@ -1400,6 +1408,22 @@
1400
1408
  ],
1401
1409
  "execution_capabilities": ["app-mutation"]
1402
1410
  },
1411
+ "metamask.wallet.lock": {
1412
+ "description": "Lock the Mobile wallet through the visible menu and confirm the login screen.",
1413
+ "schema": {
1414
+ "type": "object",
1415
+ "properties": {
1416
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1417
+ },
1418
+ "additionalProperties": false
1419
+ },
1420
+ "examples": [{
1421
+ "action": "metamask.wallet.lock",
1422
+ "intent": "Lock the wallet through visible native controls",
1423
+ "next": "done"
1424
+ }],
1425
+ "execution_capabilities": ["app-mutation"]
1426
+ },
1403
1427
  "metamask.wallet.select_account": {
1404
1428
  "description": "mobile action to select a wallet account by address, id, or display name.",
1405
1429
  "schema": {
@@ -1535,6 +1559,184 @@
1535
1559
  ],
1536
1560
  "execution_capabilities": ["host-read-export"]
1537
1561
  },
1562
+ "metamask.assets.open_details": {
1563
+ "description": "Open one visible Mobile asset by symbol through native accessibility.",
1564
+ "schema": {
1565
+ "type": "object",
1566
+ "properties": {
1567
+ "symbol": { "type": "string" },
1568
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1569
+ },
1570
+ "required": ["symbol"],
1571
+ "additionalProperties": false
1572
+ },
1573
+ "examples": [{
1574
+ "action": "metamask.assets.open_details",
1575
+ "symbol": "ETH",
1576
+ "intent": "Open the funded ETH details",
1577
+ "next": "done"
1578
+ }],
1579
+ "execution_capabilities": ["app-mutation"]
1580
+ },
1581
+ "metamask.assets.read_details": {
1582
+ "description": "Read and assert the visible Mobile token details surface through native accessibility.",
1583
+ "schema": {
1584
+ "type": "object",
1585
+ "properties": {
1586
+ "expected_symbol": { "type": "string" },
1587
+ "require_chart": { "type": "boolean", "default": false },
1588
+ "require_market_cap": { "type": "boolean", "default": false },
1589
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1590
+ },
1591
+ "additionalProperties": false
1592
+ },
1593
+ "examples": [{
1594
+ "action": "metamask.assets.read_details",
1595
+ "expected_symbol": "ETH",
1596
+ "require_chart": true,
1597
+ "require_market_cap": true,
1598
+ "intent": "Prove current asset market data",
1599
+ "next": "done"
1600
+ }],
1601
+ "execution_capabilities": ["host-read-export"]
1602
+ },
1603
+ "metamask.assets.verify_sorting": {
1604
+ "description": "Select alphabetical and declining-fiat token sorting and assert the visible native row order.",
1605
+ "schema": {
1606
+ "type": "object",
1607
+ "properties": {
1608
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1609
+ },
1610
+ "additionalProperties": false
1611
+ },
1612
+ "examples": [{
1613
+ "action": "metamask.assets.verify_sorting",
1614
+ "intent": "Verify both token-list sort modes",
1615
+ "next": "done"
1616
+ }],
1617
+ "execution_capabilities": ["app-mutation"]
1618
+ },
1619
+ "metamask.assets.set_token_visibility": {
1620
+ "description": "Import or remove one Mobile token through visible native controls and verify the resulting state.",
1621
+ "schema": {
1622
+ "type": "object",
1623
+ "properties": {
1624
+ "query": { "type": "string" },
1625
+ "visible": { "type": "boolean" },
1626
+ "require_unchanged": { "type": "boolean", "default": false },
1627
+ "require_change": { "type": "boolean", "default": false },
1628
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 45000 }
1629
+ },
1630
+ "required": ["query", "visible"],
1631
+ "additionalProperties": false
1632
+ },
1633
+ "examples": [{
1634
+ "action": "metamask.assets.set_token_visibility",
1635
+ "query": "DAI",
1636
+ "visible": true,
1637
+ "intent": "Import DAI through visible token search",
1638
+ "next": "done"
1639
+ }],
1640
+ "execution_capabilities": ["app-mutation"]
1641
+ },
1642
+ "metamask.assets.import_custom_token": {
1643
+ "description": "Import one ERC-20 on a selected Mobile network through the visible custom-token form and verify its row.",
1644
+ "schema": {
1645
+ "type": "object",
1646
+ "properties": {
1647
+ "network": { "type": "string" },
1648
+ "chain_id": { "type": "integer", "minimum": 1 },
1649
+ "address": { "type": "string" },
1650
+ "expected_symbol": { "type": "string" },
1651
+ "decimals": { "type": "integer", "minimum": 0 },
1652
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
1653
+ },
1654
+ "required": ["network", "chain_id", "address", "expected_symbol"],
1655
+ "additionalProperties": false
1656
+ },
1657
+ "examples": [{
1658
+ "action": "metamask.assets.import_custom_token",
1659
+ "network": "Arbitrum",
1660
+ "chain_id": 42161,
1661
+ "address": "0xDA10009cbd5D07dd0CeCc66161FC93D7c9000da1",
1662
+ "expected_symbol": "DAI",
1663
+ "decimals": 18,
1664
+ "intent": "Import Arbitrum DAI by contract address",
1665
+ "next": "done"
1666
+ }],
1667
+ "execution_capabilities": ["app-mutation"]
1668
+ },
1669
+ "metamask.networks.read_visible_state": {
1670
+ "description": "Read one Mobile network from visible network settings and prove it persists across a bounded settle window.",
1671
+ "schema": {
1672
+ "type": "object",
1673
+ "properties": {
1674
+ "network": { "type": "string" },
1675
+ "chain_id": { "type": "integer", "minimum": 1 },
1676
+ "settle_ms": { "type": "integer", "minimum": 0, "default": 0 },
1677
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1678
+ },
1679
+ "required": ["network", "chain_id"],
1680
+ "additionalProperties": false
1681
+ },
1682
+ "examples": [{
1683
+ "action": "metamask.networks.read_visible_state",
1684
+ "network": "PulseChain",
1685
+ "chain_id": 369,
1686
+ "settle_ms": 1000,
1687
+ "intent": "Prove PulseChain remains in Mobile network settings",
1688
+ "next": "done"
1689
+ }],
1690
+ "execution_capabilities": ["host-read-export"]
1691
+ },
1692
+ "metamask.networks.add_custom": {
1693
+ "description": "Add or locate one custom Mobile network through visible native network settings.",
1694
+ "schema": {
1695
+ "type": "object",
1696
+ "properties": {
1697
+ "network": { "type": "string" },
1698
+ "rpc_url": { "type": "string" },
1699
+ "chain_id": { "type": "integer", "minimum": 1 },
1700
+ "symbol": { "type": "string" },
1701
+ "explorer_url": { "type": "string" },
1702
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
1703
+ },
1704
+ "required": ["network", "rpc_url", "chain_id", "symbol"],
1705
+ "additionalProperties": false
1706
+ },
1707
+ "examples": [{
1708
+ "action": "metamask.networks.add_custom",
1709
+ "network": "PulseChain",
1710
+ "rpc_url": "https://rpc.pulsechain.com",
1711
+ "chain_id": 369,
1712
+ "symbol": "PLS",
1713
+ "explorer_url": "https://scan.pulsechain.com",
1714
+ "intent": "Add PulseChain through Mobile network settings",
1715
+ "next": "done"
1716
+ }],
1717
+ "execution_capabilities": ["app-mutation"]
1718
+ },
1719
+ "metamask.networks.remove_custom": {
1720
+ "description": "Remove one custom Mobile network through visible native network settings.",
1721
+ "schema": {
1722
+ "type": "object",
1723
+ "properties": {
1724
+ "network": { "type": "string" },
1725
+ "chain_id": { "type": "integer", "minimum": 1 },
1726
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1727
+ },
1728
+ "required": ["network", "chain_id"],
1729
+ "additionalProperties": false
1730
+ },
1731
+ "examples": [{
1732
+ "action": "metamask.networks.remove_custom",
1733
+ "network": "PulseChain",
1734
+ "chain_id": 369,
1735
+ "intent": "Remove PulseChain through Mobile network settings",
1736
+ "next": "done"
1737
+ }],
1738
+ "execution_capabilities": ["app-mutation"]
1739
+ },
1538
1740
  "metamask.swap_bridge.read_visible_state": {
1539
1741
  "description": "Read and assert the visible Swap surface from an opaque Mobile runtime through native accessibility.",
1540
1742
  "schema": {
@@ -1543,7 +1745,9 @@
1543
1745
  "source_symbol": { "type": "string" },
1544
1746
  "destination_symbol": { "type": "string" },
1545
1747
  "require_amount_inputs": { "type": "boolean", "default": true },
1546
- "require_settings": { "type": "boolean", "default": false }
1748
+ "require_settings": { "type": "boolean", "default": false },
1749
+ "require_quote": { "type": "boolean", "default": false },
1750
+ "expected_slippage": { "type": "number", "minimum": 0 }
1547
1751
  },
1548
1752
  "additionalProperties": false
1549
1753
  },
@@ -1558,6 +1762,68 @@
1558
1762
  ],
1559
1763
  "execution_capabilities": ["host-read-export"]
1560
1764
  },
1765
+ "metamask.swap_bridge.set_slippage": {
1766
+ "description": "Set a custom Swap slippage percentage through native accessibility.",
1767
+ "schema": {
1768
+ "type": "object",
1769
+ "properties": {
1770
+ "percent": { "type": "number", "minimum": 0.01 },
1771
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1772
+ },
1773
+ "required": ["percent"],
1774
+ "additionalProperties": false
1775
+ },
1776
+ "examples": [{
1777
+ "action": "metamask.swap_bridge.set_slippage",
1778
+ "percent": 3,
1779
+ "intent": "Set the release checklist custom slippage value",
1780
+ "next": "done"
1781
+ }],
1782
+ "execution_capabilities": ["app-mutation"]
1783
+ },
1784
+ "metamask.swap_bridge.submit_transaction": {
1785
+ "description": "Submit an explicitly authorized live Mobile Swap and prove its terminal post-trade status and visible Activity entry.",
1786
+ "schema": {
1787
+ "type": "object",
1788
+ "properties": {
1789
+ "source_symbol": { "type": "string" },
1790
+ "destination_symbol": { "type": "string" },
1791
+ "amount": { "type": ["string", "number"] },
1792
+ "confirm_live": { "type": "boolean", "default": false },
1793
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 300000 }
1794
+ },
1795
+ "required": ["source_symbol", "destination_symbol", "amount"],
1796
+ "additionalProperties": false
1797
+ },
1798
+ "examples": [{
1799
+ "action": "metamask.swap_bridge.submit_transaction",
1800
+ "source_symbol": "ETH",
1801
+ "destination_symbol": "DAI",
1802
+ "amount": "0.00005",
1803
+ "confirm_live": true,
1804
+ "intent": "Submit the authorized release-check Swap and prove its Activity entry",
1805
+ "next": "done"
1806
+ }],
1807
+ "execution_capabilities": ["app-mutation", "external-mutation"]
1808
+ },
1809
+ "metamask.swap_bridge.set_max_amount": {
1810
+ "description": "Use the visible Swap Max control and wait for the derived live quote through native accessibility.",
1811
+ "schema": {
1812
+ "type": "object",
1813
+ "properties": {
1814
+ "wait_for_quote": { "type": "boolean", "default": true },
1815
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
1816
+ },
1817
+ "additionalProperties": false
1818
+ },
1819
+ "examples": [{
1820
+ "action": "metamask.swap_bridge.set_max_amount",
1821
+ "wait_for_quote": true,
1822
+ "intent": "Use the available token balance for the return Swap",
1823
+ "next": "done"
1824
+ }],
1825
+ "execution_capabilities": ["app-mutation"]
1826
+ },
1561
1827
  "metamask.swap_bridge.select_assets": {
1562
1828
  "description": "Select exact Swap source and destination assets through native accessibility.",
1563
1829
  "schema": {
@@ -1698,6 +1964,47 @@
1698
1964
  ],
1699
1965
  "execution_capabilities": ["host-read-export"]
1700
1966
  },
1967
+ "metamask.perps.search_markets": {
1968
+ "description": "Enter a Perps market query through native accessibility and prove visible results are returned.",
1969
+ "schema": {
1970
+ "type": "object",
1971
+ "properties": {
1972
+ "query": { "type": "string" },
1973
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1974
+ },
1975
+ "required": ["query"],
1976
+ "additionalProperties": false
1977
+ },
1978
+ "examples": [{
1979
+ "action": "metamask.perps.search_markets",
1980
+ "query": "Bitcoin",
1981
+ "intent": "Filter the visible Perps market list",
1982
+ "next": "done"
1983
+ }],
1984
+ "execution_capabilities": ["app-mutation"]
1985
+ },
1986
+ "metamask.perps.set_market_favorite": {
1987
+ "description": "Converge one visible Perps market watchlist state through native accessibility.",
1988
+ "schema": {
1989
+ "type": "object",
1990
+ "properties": {
1991
+ "market": { "type": "string" },
1992
+ "favorite": { "type": "boolean" },
1993
+ "require_unchanged": { "type": "boolean", "default": false },
1994
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
1995
+ },
1996
+ "required": ["market", "favorite"],
1997
+ "additionalProperties": false
1998
+ },
1999
+ "examples": [{
2000
+ "action": "metamask.perps.set_market_favorite",
2001
+ "market": "BTC",
2002
+ "favorite": true,
2003
+ "intent": "Ensure BTC appears in the Perps watchlist",
2004
+ "next": "done"
2005
+ }],
2006
+ "execution_capabilities": ["app-mutation"]
2007
+ },
1701
2008
  "metamask.perps.read_positions": {
1702
2009
  "description": "mobile Read live Perps positions; without a selector, return all live positions.",
1703
2010
  "schema": {
@@ -21,10 +21,10 @@
21
21
  "next": "open-first-asset"
22
22
  },
23
23
  "open-first-asset": {
24
- "action": "ui.press",
25
- "test_id": "multichain-token-list-button",
26
- "settle": true,
27
- "intent": "Open the first visible funded asset through a trusted pointer",
24
+ "action": "metamask.assets.open_details",
25
+ "symbol": "{{params.symbol}}",
26
+ "timeout_ms": "{{params.timeout_ms}}",
27
+ "intent": "Open the requested visible funded asset",
28
28
  "next": "assert-details"
29
29
  },
30
30
  "assert-details": {
@@ -32,6 +32,7 @@
32
32
  "expected_symbol": "{{params.symbol}}",
33
33
  "require_chart": true,
34
34
  "require_market_cap": true,
35
+ "timeout_ms": "{{params.timeout_ms}}",
35
36
  "intent": "Prove live asset price history and market data render without malformed values",
36
37
  "next": "capture-details"
37
38
  },
@@ -23,6 +23,7 @@
23
23
  "action": "metamask.assets.set_token_visibility",
24
24
  "query": "{{params.query}}",
25
25
  "visible": false,
26
+ "require_change": true,
26
27
  "timeout_ms": "{{params.timeout_ms}}",
27
28
  "intent": "Disable the imported token and prove its row disappears",
28
29
  "next": "capture-hidden"
@@ -38,6 +39,7 @@
38
39
  "action": "metamask.assets.set_token_visibility",
39
40
  "query": "{{params.query}}",
40
41
  "visible": true,
42
+ "require_change": true,
41
43
  "timeout_ms": "{{params.timeout_ms}}",
42
44
  "intent": "Re-enable the token and prove its metadata row returns",
43
45
  "next": "capture-restored"
@@ -0,0 +1,90 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Mobile release custom-network persistence",
4
+ "description": "Adds a custom network through native settings, proves it survives lock/unlock, and removes it.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "network": { "type": "string", "default": "PulseChain" },
10
+ "rpc_url": { "type": "string", "default": "https://rpc.pulsechain.com" },
11
+ "chain_id": { "type": "integer", "minimum": 1, "default": 369 },
12
+ "symbol": { "type": "string", "default": "PLS" },
13
+ "explorer_url": { "type": "string", "default": "https://scan.pulsechain.com" },
14
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
15
+ }
16
+ },
17
+ "workflow": {
18
+ "entry": "open-wallet",
19
+ "nodes": {
20
+ "open-wallet": {
21
+ "action": "ui.navigate",
22
+ "page": "home",
23
+ "intent": "Open the wallet before custom-network setup",
24
+ "next": "add-network"
25
+ },
26
+ "add-network": {
27
+ "action": "metamask.networks.add_custom",
28
+ "network": "{{params.network}}",
29
+ "rpc_url": "{{params.rpc_url}}",
30
+ "chain_id": "{{params.chain_id}}",
31
+ "symbol": "{{params.symbol}}",
32
+ "explorer_url": "{{params.explorer_url}}",
33
+ "timeout_ms": "{{params.timeout_ms}}",
34
+ "intent": "Add the custom network through visible settings",
35
+ "next": "assert-added"
36
+ },
37
+ "assert-added": {
38
+ "action": "metamask.networks.read_visible_state",
39
+ "network": "{{params.network}}",
40
+ "chain_id": "{{params.chain_id}}",
41
+ "settle_ms": 1000,
42
+ "timeout_ms": "{{params.timeout_ms}}",
43
+ "intent": "Prove the custom network is present",
44
+ "next": "capture-before"
45
+ },
46
+ "capture-before": {
47
+ "action": "ui.screenshot",
48
+ "path": "screenshots/custom-network-before-lock.png",
49
+ "label": "Custom network before lock",
50
+ "intent": "Preserve pre-lock network evidence",
51
+ "next": "lock-wallet"
52
+ },
53
+ "lock-wallet": {
54
+ "action": "metamask.wallet.lock",
55
+ "intent": "Lock the wallet through visible native controls",
56
+ "next": "unlock-wallet"
57
+ },
58
+ "unlock-wallet": {
59
+ "action": "metamask.wallet.ensure_unlocked",
60
+ "intent": "Unlock the same persisted profile",
61
+ "next": "assert-persisted"
62
+ },
63
+ "assert-persisted": {
64
+ "action": "metamask.networks.read_visible_state",
65
+ "network": "{{params.network}}",
66
+ "chain_id": "{{params.chain_id}}",
67
+ "settle_ms": 1000,
68
+ "timeout_ms": "{{params.timeout_ms}}",
69
+ "intent": "Prove the custom network survived lock and unlock",
70
+ "next": "capture-after"
71
+ },
72
+ "capture-after": {
73
+ "action": "ui.screenshot",
74
+ "path": "screenshots/custom-network-after-unlock.png",
75
+ "label": "Custom network after unlock",
76
+ "intent": "Preserve post-unlock network evidence",
77
+ "next": "remove-network"
78
+ },
79
+ "remove-network": {
80
+ "action": "metamask.networks.remove_custom",
81
+ "network": "{{params.network}}",
82
+ "chain_id": "{{params.chain_id}}",
83
+ "timeout_ms": "{{params.timeout_ms}}",
84
+ "intent": "Remove the custom network and prove it is absent",
85
+ "next": "done"
86
+ },
87
+ "done": { "action": "end", "status": "pass" }
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Mobile multi-network asset visibility",
4
+ "description": "Proves funded assets from multiple protocol families are visible together in the opaque Mobile wallet.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "symbols": {
10
+ "type": "array",
11
+ "items": { "type": "string" },
12
+ "default": ["ETH", "SOL"]
13
+ },
14
+ "minimum_asset_count": {
15
+ "type": "integer",
16
+ "minimum": 2,
17
+ "default": 2
18
+ },
19
+ "timeout_ms": {
20
+ "type": "integer",
21
+ "minimum": 1000,
22
+ "default": 45000
23
+ }
24
+ }
25
+ },
26
+ "workflow": {
27
+ "entry": "open-wallet",
28
+ "nodes": {
29
+ "open-wallet": {
30
+ "action": "ui.navigate",
31
+ "page": "home",
32
+ "timeout_ms": "{{params.timeout_ms}}",
33
+ "intent": "Open the aggregate Mobile wallet token list",
34
+ "next": "assert-multichain-assets"
35
+ },
36
+ "assert-multichain-assets": {
37
+ "action": "metamask.assets.read_visible_state",
38
+ "require_symbols": "{{params.symbols}}",
39
+ "minimum_asset_count": "{{params.minimum_asset_count}}",
40
+ "require_fiat": true,
41
+ "max_items": 100,
42
+ "intent": "Prove assets from the requested protocol families are simultaneously visible",
43
+ "next": "capture-wallet"
44
+ },
45
+ "capture-wallet": {
46
+ "action": "ui.screenshot",
47
+ "path": "screenshots/mobile-multichain-assets.png",
48
+ "label": "Mobile multi-network asset visibility",
49
+ "intent": "Preserve reviewer-visible proof of aggregate multi-network holdings",
50
+ "next": "done"
51
+ },
52
+ "done": {
53
+ "action": "end",
54
+ "status": "pass"
55
+ }
56
+ }
57
+ }
58
+ }
@@ -18,6 +18,11 @@
18
18
  "type": "integer",
19
19
  "minimum": 1,
20
20
  "default": 3
21
+ },
22
+ "minimum_unfiltered_results": {
23
+ "type": "integer",
24
+ "minimum": 1,
25
+ "default": 5
21
26
  }
22
27
  }
23
28
  },
@@ -39,16 +44,15 @@
39
44
  "assert-unfiltered": {
40
45
  "action": "metamask.perps.read_visible_state",
41
46
  "surface": "market-list",
42
- "minimum_market_count": 20,
47
+ "minimum_market_count": "{{params.minimum_unfiltered_results}}",
43
48
  "require_features": ["market-list"],
44
49
  "max_items": 100,
45
50
  "intent": "Prove the live market list is populated before filtering",
46
51
  "next": "search"
47
52
  },
48
53
  "search": {
49
- "action": "ui.set_input",
50
- "test_id": "search-input",
51
- "value": "{{params.query}}",
54
+ "action": "metamask.perps.search_markets",
55
+ "query": "{{params.query}}",
52
56
  "intent": "Enter the market search through trusted keyboard input",
53
57
  "next": "assert-filtered"
54
58
  },
@@ -45,28 +45,27 @@
45
45
  "action": "ui.navigate",
46
46
  "page": "perps",
47
47
  "intent": "Show Perps home after adding the favorite",
48
- "next": "assert-added"
48
+ "next": "reopen-market-list-added"
49
49
  },
50
- "assert-added": {
51
- "action": "metamask.perps.read_visible_state",
52
- "surface": "home",
53
- "market": "{{params.market}}",
54
- "require_test_ids": ["perps-watchlist-{{params.market}}"],
55
- "max_items": 150,
56
- "intent": "Prove the favorite persists on the home watchlist",
57
- "next": "reopen-market-list"
58
- },
59
- "reopen-market-list": {
50
+ "reopen-market-list-added": {
60
51
  "action": "ui.navigate",
61
52
  "page": "perps-market-list",
62
- "intent": "Reopen the complete market list",
63
- "next": "reopen-market"
53
+ "intent": "Reopen the market list after adding the favorite",
54
+ "next": "reopen-market-added"
64
55
  },
65
- "reopen-market": {
56
+ "reopen-market-added": {
66
57
  "action": "ui.navigate",
67
58
  "page": "perps-market",
68
59
  "market": "{{params.market}}",
69
60
  "intent": "Reopen the favorited market",
61
+ "next": "assert-added"
62
+ },
63
+ "assert-added": {
64
+ "action": "metamask.perps.set_market_favorite",
65
+ "market": "{{params.market}}",
66
+ "favorite": true,
67
+ "require_unchanged": true,
68
+ "intent": "Prove the favorite persisted after navigating away and back",
70
69
  "next": "remove-favorite"
71
70
  },
72
71
  "remove-favorite": {
@@ -80,14 +79,27 @@
80
79
  "action": "ui.navigate",
81
80
  "page": "perps",
82
81
  "intent": "Show Perps home after removing the favorite",
82
+ "next": "reopen-market-list-removed"
83
+ },
84
+ "reopen-market-list-removed": {
85
+ "action": "ui.navigate",
86
+ "page": "perps-market-list",
87
+ "intent": "Reopen the market list after removing the favorite",
88
+ "next": "reopen-market-removed"
89
+ },
90
+ "reopen-market-removed": {
91
+ "action": "ui.navigate",
92
+ "page": "perps-market",
93
+ "market": "{{params.market}}",
94
+ "intent": "Reopen the unfavorited market",
83
95
  "next": "assert-removed"
84
96
  },
85
97
  "assert-removed": {
86
- "action": "metamask.perps.read_visible_state",
87
- "surface": "home",
88
- "forbid_test_ids": ["perps-watchlist-{{params.market}}"],
89
- "max_items": 150,
90
- "intent": "Prove the removed favorite no longer appears on the watchlist",
98
+ "action": "metamask.perps.set_market_favorite",
99
+ "market": "{{params.market}}",
100
+ "favorite": false,
101
+ "require_unchanged": true,
102
+ "intent": "Prove the removal persisted after navigating away and back",
91
103
  "next": "done"
92
104
  },
93
105
  "done": {