@deeeed/metamask-harness 0.39.0 → 0.40.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 (67) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/adapters/extension/lib/playwright-cdp.cjs +17 -1
  3. package/adapters/extension/sidepanel-toggle.sh +135 -13
  4. package/dist/adapters/mobile/release-artifact.js +65 -0
  5. package/dist/adapters.js +8 -7
  6. package/dist/command-contract.js +10 -2
  7. package/dist/commands/call.js +7 -4
  8. package/dist/commands/launch/index.js +55 -3
  9. package/dist/commands/parse-args.js +6 -0
  10. package/dist/commands/run-engine.js +75 -39
  11. package/dist/funding-execution-context.js +1386 -0
  12. package/dist/live-adapter-contract.js +3 -1
  13. package/dist/metamask-action-validation.js +170 -3
  14. package/dist/mm-harness-cli.js +8 -2
  15. package/dist/recipe-security.js +5 -12
  16. package/dist/runner.js +102 -6
  17. package/docs/RECIPES.md +74 -1
  18. package/docs/RELEASE-QA-CAPABILITY-MAP.md +6 -5
  19. package/library/actions/extension/networks/add_chainlist.mjs +4 -0
  20. package/library/actions/extension/networks/add_custom.mjs +4 -0
  21. package/library/actions/extension/networks/custom_network.mjs +48 -1
  22. package/library/actions/extension/perps/assert_visible_consistency.mjs +366 -0
  23. package/library/actions/extension/perps/close_visible_position.mjs +299 -37
  24. package/library/actions/extension/perps/compare_provider_market.mjs +77 -0
  25. package/library/actions/extension/perps/edit_margin.mjs +285 -44
  26. package/library/actions/extension/perps/mutation-receipt.mjs +781 -0
  27. package/library/actions/extension/perps/perps.mjs +1029 -363
  28. package/library/actions/extension/perps/read_funds_confirmation.mjs +126 -13
  29. package/library/actions/extension/perps/read_snapshot.mjs +124 -3
  30. package/library/actions/extension/perps/read_visible_state.mjs +63 -5
  31. package/library/actions/extension/perps/select_activity_filter.mjs +81 -18
  32. package/library/actions/extension/perps/select_market_filter.mjs +48 -4
  33. package/library/actions/extension/perps/update_position_tpsl.mjs +251 -69
  34. package/library/actions/extension/perps/visible-mutation-identity.mjs +164 -0
  35. package/library/actions/extension/platform/cdp.mjs +88 -9
  36. package/library/actions/extension/settings/set_basic_functionality.mjs +35 -7
  37. package/library/actions/extension/ui/navigate.mjs +45 -5
  38. package/library/actions/extension/wallet/import.mjs +70 -29
  39. package/library/actions/extension/wallet/lock.mjs +62 -5
  40. package/library/actions/extension/wallet/visible-session.mjs +218 -0
  41. package/library/actions/mobile/ui/native-navigation.mjs +45 -0
  42. package/library/actions/mobile/wallet/import.mjs +17 -10
  43. package/library/actions/mobile/wallet/native-ui.mjs +21 -1
  44. package/library/actions/shared/perps/visible-state.mjs +25 -5
  45. package/library/manifests/extension.action-manifest.json +1696 -1271
  46. package/library/recipes/extension/assets/release-custom-network-token-persistence.recipe.json +1 -0
  47. package/library/recipes/{perps → extension/perps}/release-activity-filters.recipe.json +5 -5
  48. package/library/recipes/{perps → extension/perps}/release-funds-flows.recipe.json +3 -3
  49. package/library/recipes/extension/perps/release-live-limit-order.recipe.json +24 -19
  50. package/library/recipes/extension/perps/release-market-filters.recipe.json +97 -0
  51. package/library/recipes/extension/perps/release-order-entry.recipe.json +4 -1
  52. package/library/recipes/extension/perps/release-order-validation.recipe.json +53 -14
  53. package/library/recipes/extension/perps/release-visible-consistency.recipe.json +47 -0
  54. package/library/recipes/extension/perps/source-dev-snapshot-consistency.recipe.json +76 -0
  55. package/library/recipes/perps/release-live-market-order.recipe.json +30 -13
  56. package/library/recipes/perps/release-market-details.recipe.json +1 -1
  57. package/library/recipes/swap-bridge/release-quote.recipe.json +1 -0
  58. package/library/recipes/wallet/import.recipe.json +4 -14
  59. package/package.json +1 -1
  60. package/library/actions/extension/assets/finish_send.mjs +0 -128
  61. package/library/actions/extension/swap_bridge/submit_transaction.mjs +0 -363
  62. package/library/actions/extension/ui/activate_and_observe.mjs +0 -96
  63. package/library/recipes/assets/release-custom-gas-send.recipe.json +0 -88
  64. package/library/recipes/assets/release-native-max-cancel.recipe.json +0 -70
  65. package/library/recipes/assets/release-native-max-send.recipe.json +0 -78
  66. package/library/recipes/assets/release-own-account-send.recipe.json +0 -80
  67. package/library/recipes/extension/runner/action-validation.recipe.json +0 -343
@@ -33,6 +33,7 @@
33
33
  "chain_id": "{{params.chain_id}}",
34
34
  "symbol": "{{params.native_symbol}}",
35
35
  "explorer_url": "{{params.explorer_url}}",
36
+ "require_absent": true,
36
37
  "timeout_ms": "{{params.timeout_ms}}",
37
38
  "intent": "Add and select the custom network through visible settings",
38
39
  "next": "import-token"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "Perps release activity filters",
4
- "description": "Opens live Perps activity and exercises the Trades, Orders, Funding, and Deposits filters through semantic visible controls.",
4
+ "description": "Selects the Trades, Orders, Funding, and Deposits controls and proves each selected label and route; populated or typed activity rows are not required.",
5
5
  "workflow": {
6
6
  "entry": "open-activity",
7
7
  "nodes": {
@@ -14,25 +14,25 @@
14
14
  "trades": {
15
15
  "action": "metamask.perps.select_activity_filter",
16
16
  "filter": "trades",
17
- "intent": "Show only trade-related Perps activity",
17
+ "intent": "Prove the Trades filter label and route",
18
18
  "next": "orders"
19
19
  },
20
20
  "orders": {
21
21
  "action": "metamask.perps.select_activity_filter",
22
22
  "filter": "orders",
23
- "intent": "Show only order-related Perps activity",
23
+ "intent": "Prove the Orders filter label and route",
24
24
  "next": "funding"
25
25
  },
26
26
  "funding": {
27
27
  "action": "metamask.perps.select_activity_filter",
28
28
  "filter": "funding",
29
- "intent": "Show only Perps funding activity",
29
+ "intent": "Prove the Funding filter label and route",
30
30
  "next": "deposits"
31
31
  },
32
32
  "deposits": {
33
33
  "action": "metamask.perps.select_activity_filter",
34
34
  "filter": "deposits",
35
- "intent": "Show only Perps deposit and withdrawal activity",
35
+ "intent": "Prove the Deposits filter label and route",
36
36
  "next": "capture"
37
37
  },
38
38
  "capture": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "Perps release funds flows",
4
- "description": "Opens the live Perps deposit and withdraw confirmations, proves their loaded amount contexts, and dismisses each without submitting funds.",
4
+ "description": "Opens the live Perps deposit and withdraw forms, records the currently rendered preview fields, proves zero withdrawal is disabled, and dismisses both without submission.",
5
5
  "workflow": {
6
6
  "entry": "open-perps-deposit",
7
7
  "nodes": {
@@ -20,7 +20,7 @@
20
20
  "read-deposit": {
21
21
  "action": "metamask.perps.read_funds_confirmation",
22
22
  "mode": "deposit",
23
- "intent": "Prove the deposit amount, token, fee, and time context loaded",
23
+ "intent": "Prove the deposit form loaded and record any rendered preview fields",
24
24
  "next": "dismiss-deposit"
25
25
  },
26
26
  "dismiss-deposit": {
@@ -44,7 +44,7 @@
44
44
  "read-withdraw": {
45
45
  "action": "metamask.perps.read_funds_confirmation",
46
46
  "mode": "withdraw",
47
- "intent": "Prove available balance, receive token, fee, time, and final amount loaded",
47
+ "intent": "Prove the withdraw form loaded and record any rendered preview fields",
48
48
  "next": "enter-zero"
49
49
  },
50
50
  "enter-zero": {
@@ -5,7 +5,7 @@
5
5
  "paramsSchema": {
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
- "required": ["confirm_live"],
8
+ "required": ["confirm_live", "limit_price", "provider", "network"],
9
9
  "properties": {
10
10
  "market": {
11
11
  "type": "string",
@@ -19,15 +19,16 @@
19
19
  "leverage": {
20
20
  "type": "integer",
21
21
  "minimum": 1,
22
- "default": 3
23
- },
24
- "offset_pct": {
25
- "type": "number",
26
- "default": -2
22
+ "default": 1
27
23
  },
24
+ "provider": { "type": "string" },
25
+ "network": { "type": "string", "enum": ["mainnet", "testnet"] },
26
+ "limit_price": { "type": "string" },
27
+ "offset_pct": { "type": "number" },
28
28
  "confirm_live": {
29
29
  "type": "boolean"
30
- }
30
+ },
31
+ "identity_rounding_tolerance_base_units": { "type": "string", "default": "10000" }
31
32
  }
32
33
  },
33
34
  "workflow": {
@@ -38,14 +39,6 @@
38
39
  "page": "perps-market",
39
40
  "market": "{{params.market}}",
40
41
  "intent": "Open the requested live Perps market",
41
- "next": "assert-clean"
42
- },
43
- "assert-clean": {
44
- "action": "metamask.perps.read_visible_state",
45
- "surface": "market-details",
46
- "market": "{{params.market}}",
47
- "maximum_order_count": 0,
48
- "intent": "Prove no order is open before submission",
49
42
  "next": "place-limit"
50
43
  },
51
44
  "place-limit": {
@@ -54,9 +47,13 @@
54
47
  "side": "long",
55
48
  "amount": "{{params.amount}}",
56
49
  "leverage": "{{params.leverage}}",
50
+ "provider": "{{params.provider}}",
51
+ "network": "{{params.network}}",
57
52
  "order_type": "limit",
58
- "offset_pct": "{{params.offset_pct}}",
53
+ "limit_price": "{{params.limit_price}}",
59
54
  "confirm_live": "{{params.confirm_live}}",
55
+ "identity_rounding_tolerance_base_units": "{{params.identity_rounding_tolerance_base_units}}",
56
+ "submit_attempts": 1,
60
57
  "timeout_ms": 45000,
61
58
  "intent": "Submit one authorized resting limit order through visible controls",
62
59
  "next": "assert-open"
@@ -82,6 +79,13 @@
82
79
  "cancel-order": {
83
80
  "action": "metamask.perps.close_orders",
84
81
  "market": "{{params.market}}",
82
+ "side": "long",
83
+ "amount": "{{params.amount}}",
84
+ "leverage": "{{params.leverage}}",
85
+ "provider": "{{params.provider}}",
86
+ "network": "{{params.network}}",
87
+ "limit_price": "{{params.limit_price}}",
88
+ "identity_rounding_tolerance_base_units": "{{params.identity_rounding_tolerance_base_units}}",
85
89
  "confirm_live": "{{params.confirm_live}}",
86
90
  "timeout_ms": 30000,
87
91
  "intent": "Cancel the authorized live limit order through visible controls",
@@ -89,10 +93,11 @@
89
93
  },
90
94
  "assert-canceled": {
91
95
  "action": "metamask.perps.read_visible_state",
92
- "surface": "market-details",
93
- "market": "{{params.market}}",
96
+ "surface": "home",
97
+ "maximum_position_count": 0,
94
98
  "maximum_order_count": 0,
95
- "intent": "Prove the order card disappears after cancellation",
99
+ "require_features": ["balance", "market-list"],
100
+ "intent": "Prove global positions and orders remain empty after cancellation",
96
101
  "next": "done"
97
102
  },
98
103
  "done": {
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Perps release market filters",
4
+ "description": "Exercises every stable live Perps market category through visible controls after resetting the market-list surface.",
5
+ "workflow": {
6
+ "entry": "open-perps",
7
+ "nodes": {
8
+ "open-perps": {
9
+ "action": "ui.navigate",
10
+ "page": "perps",
11
+ "intent": "Reset transient market-list state on the Perps home surface",
12
+ "next": "open-market-list"
13
+ },
14
+ "open-market-list": {
15
+ "action": "ui.navigate",
16
+ "page": "perps-market-list",
17
+ "intent": "Open the complete live Perps market selection",
18
+ "next": "wait-market-filter"
19
+ },
20
+ "wait-market-filter": {
21
+ "action": "ui.wait_for",
22
+ "test_id": "filter-select-button",
23
+ "expected": "visible",
24
+ "timeout_ms": 30000,
25
+ "intent": "Confirm the market filter control is ready",
26
+ "next": "all"
27
+ },
28
+ "all": {
29
+ "action": "metamask.perps.select_market_filter",
30
+ "filter": "all",
31
+ "minimum_market_count": 1,
32
+ "intent": "Prove the complete live market category",
33
+ "next": "crypto"
34
+ },
35
+ "crypto": {
36
+ "action": "metamask.perps.select_market_filter",
37
+ "filter": "crypto",
38
+ "minimum_market_count": 0,
39
+ "intent": "Prove the Crypto market category",
40
+ "next": "stocks"
41
+ },
42
+ "stocks": {
43
+ "action": "metamask.perps.select_market_filter",
44
+ "filter": "stocks",
45
+ "minimum_market_count": 0,
46
+ "intent": "Prove the Stocks market category",
47
+ "next": "pre-ipo"
48
+ },
49
+ "pre-ipo": {
50
+ "action": "metamask.perps.select_market_filter",
51
+ "filter": "pre-ipo",
52
+ "minimum_market_count": 0,
53
+ "intent": "Prove the Pre-IPO market category control",
54
+ "next": "index"
55
+ },
56
+ "index": {
57
+ "action": "metamask.perps.select_market_filter",
58
+ "filter": "index",
59
+ "minimum_market_count": 0,
60
+ "intent": "Prove the Index market category control",
61
+ "next": "etf"
62
+ },
63
+ "etf": {
64
+ "action": "metamask.perps.select_market_filter",
65
+ "filter": "etf",
66
+ "minimum_market_count": 0,
67
+ "intent": "Prove the ETF market category control",
68
+ "next": "commodities"
69
+ },
70
+ "commodities": {
71
+ "action": "metamask.perps.select_market_filter",
72
+ "filter": "commodities",
73
+ "minimum_market_count": 0,
74
+ "intent": "Prove the Commodities market category",
75
+ "next": "forex"
76
+ },
77
+ "forex": {
78
+ "action": "metamask.perps.select_market_filter",
79
+ "filter": "forex",
80
+ "minimum_market_count": 0,
81
+ "intent": "Prove the Forex market category",
82
+ "next": "capture"
83
+ },
84
+ "capture": {
85
+ "action": "ui.screenshot",
86
+ "path": "screenshots/perps-market-filters.png",
87
+ "label": "Perps release market filters",
88
+ "intent": "Preserve reviewer-visible proof of the final market filter",
89
+ "next": "done"
90
+ },
91
+ "done": {
92
+ "action": "end",
93
+ "status": "pass"
94
+ }
95
+ }
96
+ }
97
+ }
@@ -5,10 +5,13 @@
5
5
  "paramsSchema": {
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
+ "required": [
9
+ "market"
10
+ ],
8
11
  "properties": {
9
12
  "market": {
10
13
  "type": "string",
11
- "default": "BTC"
14
+ "description": "Perps market with no existing position so the New Long and Short controls are available."
12
15
  },
13
16
  "amount": {
14
17
  "type": "string",
@@ -5,10 +5,49 @@
5
5
  "paramsSchema": {
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
+ "required": [
9
+ "market"
10
+ ],
8
11
  "properties": {
9
12
  "market": {
10
13
  "type": "string",
11
- "default": "BTC"
14
+ "description": "Perps market with no existing position so the New Long order form can be validated."
15
+ },
16
+ "below_minimum_amount": {
17
+ "type": "string",
18
+ "default": "1"
19
+ },
20
+ "valid_amount": {
21
+ "type": "string",
22
+ "default": "10"
23
+ },
24
+ "percent": {
25
+ "type": "string",
26
+ "default": "50"
27
+ },
28
+ "minimum_leverage": {
29
+ "type": "string",
30
+ "default": "1"
31
+ },
32
+ "keyboard_leverage": {
33
+ "type": "string",
34
+ "default": "2"
35
+ },
36
+ "maximum_leverage": {
37
+ "type": "string",
38
+ "default": "40"
39
+ },
40
+ "invalid_take_profit": {
41
+ "type": "string",
42
+ "default": "1000"
43
+ },
44
+ "valid_take_profit": {
45
+ "type": "string",
46
+ "default": "70000"
47
+ },
48
+ "invalid_stop_loss": {
49
+ "type": "string",
50
+ "default": "100000"
12
51
  }
13
52
  }
14
53
  },
@@ -51,7 +90,7 @@
51
90
  "enter-below-minimum": {
52
91
  "action": "ui.set_input",
53
92
  "selector": "[data-testid=\"amount-input-field\"] input",
54
- "value": "1",
93
+ "value": "{{params.below_minimum_amount}}",
55
94
  "intent": "Enter an amount below the market minimum",
56
95
  "next": "assert-below-minimum"
57
96
  },
@@ -61,7 +100,7 @@
61
100
  "market": "{{params.market}}",
62
101
  "direction": "long",
63
102
  "order_type": "market",
64
- "amount": "1",
103
+ "amount": "{{params.below_minimum_amount}}",
65
104
  "submit_enabled": false,
66
105
  "max_items": 150,
67
106
  "intent": "Prove the below-minimum amount cannot be submitted",
@@ -70,14 +109,14 @@
70
109
  "enter-valid-amount": {
71
110
  "action": "ui.set_input",
72
111
  "selector": "[data-testid=\"amount-input-field\"] input",
73
- "value": "10",
112
+ "value": "{{params.valid_amount}}",
74
113
  "intent": "Enter the minimum valid USD amount",
75
114
  "next": "enter-percent"
76
115
  },
77
116
  "enter-percent": {
78
117
  "action": "ui.set_input",
79
118
  "selector": "[data-testid=\"balance-percent-input\"] input",
80
- "value": "50",
119
+ "value": "{{params.percent}}",
81
120
  "intent": "Enter a midpoint balance percentage",
82
121
  "next": "assert-percent"
83
122
  },
@@ -87,7 +126,7 @@
87
126
  "market": "{{params.market}}",
88
127
  "direction": "long",
89
128
  "order_type": "market",
90
- "percent": "50",
129
+ "percent": "{{params.percent}}",
91
130
  "submit_enabled": true,
92
131
  "max_items": 150,
93
132
  "intent": "Prove percent input updates a valid order summary",
@@ -96,7 +135,7 @@
96
135
  "enter-min-leverage": {
97
136
  "action": "ui.set_input",
98
137
  "selector": "[data-testid=\"leverage-input\"] input",
99
- "value": "1",
138
+ "value": "{{params.minimum_leverage}}",
100
139
  "intent": "Enter minimum leverage",
101
140
  "next": "assert-min-leverage"
102
141
  },
@@ -104,7 +143,7 @@
104
143
  "action": "metamask.perps.read_visible_state",
105
144
  "surface": "order-entry",
106
145
  "market": "{{params.market}}",
107
- "leverage": "1",
146
+ "leverage": "{{params.minimum_leverage}}",
108
147
  "max_items": 150,
109
148
  "intent": "Prove minimum leverage is accepted",
110
149
  "next": "raise-with-keyboard"
@@ -119,7 +158,7 @@
119
158
  "action": "metamask.perps.read_visible_state",
120
159
  "surface": "order-entry",
121
160
  "market": "{{params.market}}",
122
- "leverage": "2",
161
+ "leverage": "{{params.keyboard_leverage}}",
123
162
  "max_items": 150,
124
163
  "intent": "Prove the keyboard changes leverage by one step",
125
164
  "next": "enter-max-leverage"
@@ -127,7 +166,7 @@
127
166
  "enter-max-leverage": {
128
167
  "action": "ui.set_input",
129
168
  "selector": "[data-testid=\"leverage-input\"] input",
130
- "value": "40",
169
+ "value": "{{params.maximum_leverage}}",
131
170
  "intent": "Enter the market maximum leverage",
132
171
  "next": "assert-max-leverage"
133
172
  },
@@ -135,7 +174,7 @@
135
174
  "action": "metamask.perps.read_visible_state",
136
175
  "surface": "order-entry",
137
176
  "market": "{{params.market}}",
138
- "leverage": "40",
177
+ "leverage": "{{params.maximum_leverage}}",
139
178
  "max_items": 150,
140
179
  "intent": "Prove maximum leverage is accepted",
141
180
  "next": "enable-auto-close"
@@ -164,7 +203,7 @@
164
203
  "enter-invalid-take-profit": {
165
204
  "action": "ui.set_input",
166
205
  "selector": "[data-testid=\"tp-price-input\"] input",
167
- "value": "1000",
206
+ "value": "{{params.invalid_take_profit}}",
168
207
  "intent": "Enter a take-profit below the long entry price",
169
208
  "next": "assert-invalid-take-profit"
170
209
  },
@@ -182,14 +221,14 @@
182
221
  "enter-valid-take-profit": {
183
222
  "action": "ui.set_input",
184
223
  "selector": "[data-testid=\"tp-price-input\"] input",
185
- "value": "70000",
224
+ "value": "{{params.valid_take_profit}}",
186
225
  "intent": "Enter a take-profit above the long entry price",
187
226
  "next": "enter-invalid-stop-loss"
188
227
  },
189
228
  "enter-invalid-stop-loss": {
190
229
  "action": "ui.set_input",
191
230
  "selector": "[data-testid=\"sl-price-input\"] input",
192
- "value": "100000",
231
+ "value": "{{params.invalid_stop_loss}}",
193
232
  "intent": "Enter a stop-loss above the long entry price",
194
233
  "next": "assert-invalid-stop-loss"
195
234
  },
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Perps release visible consistency",
4
+ "description": "Proves bounded visible market-list row changes and containment of recent Perps activity across every activity filter on packaged Extension builds; it does not assert other market-detail surfaces.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "sample_count": { "type": "integer", "minimum": 2, "default": 3 },
10
+ "sample_interval_ms": { "type": "integer", "minimum": 100, "default": 1000 },
11
+ "minimum_changed_count": { "type": "integer", "minimum": 1, "default": 1 },
12
+ "minimum_recent_activity_count": { "type": "integer", "minimum": 1, "default": 1 },
13
+ "timeout_ms": { "type": "integer", "minimum": 1000, "default": 30000 }
14
+ }
15
+ },
16
+ "workflow": {
17
+ "entry": "market-stream",
18
+ "nodes": {
19
+ "market-stream": {
20
+ "action": "metamask.perps.assert_visible_consistency",
21
+ "mode": "market-stream",
22
+ "sample_count": "{{params.sample_count}}",
23
+ "sample_interval_ms": "{{params.sample_interval_ms}}",
24
+ "minimum_changed_count": "{{params.minimum_changed_count}}",
25
+ "timeout_ms": "{{params.timeout_ms}}",
26
+ "intent": "Prove bounded changes in rendered market-row facts",
27
+ "next": "activity-containment"
28
+ },
29
+ "activity-containment": {
30
+ "action": "metamask.perps.assert_visible_consistency",
31
+ "mode": "activity-containment",
32
+ "minimum_recent_activity_count": "{{params.minimum_recent_activity_count}}",
33
+ "timeout_ms": "{{params.timeout_ms}}",
34
+ "intent": "Prove recent visible activity identities are contained in full activity",
35
+ "next": "capture"
36
+ },
37
+ "capture": {
38
+ "action": "ui.screenshot",
39
+ "path": "screenshots/perps-visible-consistency.png",
40
+ "label": "Perps visible activity consistency",
41
+ "intent": "Preserve reviewer-visible proof of the full activity surface",
42
+ "next": "done"
43
+ },
44
+ "done": { "action": "end", "status": "pass" }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
+ "title": "Perps source-dev snapshot consistency",
4
+ "description": "Uses the optional source-dev Extension background hook to sample bounded Perps market data and compare one generic visible activity-card identity with normalized history.",
5
+ "paramsSchema": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "sample_count": {
10
+ "type": "integer",
11
+ "minimum": 2,
12
+ "default": 3
13
+ },
14
+ "sample_interval_ms": {
15
+ "type": "integer",
16
+ "minimum": 100,
17
+ "default": 1000
18
+ },
19
+ "minimum_changed_market_count": {
20
+ "type": "integer",
21
+ "minimum": 0,
22
+ "default": 0,
23
+ "description": "Optional live-price movement assertion. Set above zero only when the proof requires observed market changes."
24
+ },
25
+ "minimum_history_count": {
26
+ "type": "integer",
27
+ "minimum": 1,
28
+ "default": 1
29
+ }
30
+ }
31
+ },
32
+ "workflow": {
33
+ "entry": "open-activity",
34
+ "nodes": {
35
+ "open-activity": {
36
+ "action": "ui.navigate",
37
+ "page": "perps-activity",
38
+ "intent": "Open live Perps activity through visible controls",
39
+ "next": "show-funds-activity"
40
+ },
41
+ "show-funds-activity": {
42
+ "action": "metamask.perps.select_activity_filter",
43
+ "filter": "deposits",
44
+ "intent": "Show visible activity cards before generic identity comparison",
45
+ "next": "sample"
46
+ },
47
+ "sample": {
48
+ "action": "metamask.perps.read_snapshot",
49
+ "include": ["markets", "history"],
50
+ "sampling": {
51
+ "count": "{{params.sample_count}}",
52
+ "interval_ms": "{{params.sample_interval_ms}}"
53
+ },
54
+ "expect": {
55
+ "minimum_changed_market_count": "{{params.minimum_changed_market_count}}",
56
+ "minimum_history_count": "{{params.minimum_history_count}}",
57
+ "require_activity_history_agreement": true
58
+ },
59
+ "max_items_per_section": 100,
60
+ "intent": "Prove bounded market changes and one exact visible activity-to-history identity",
61
+ "next": "capture"
62
+ },
63
+ "capture": {
64
+ "action": "ui.screenshot",
65
+ "path": "screenshots/perps-snapshot-consistency.png",
66
+ "label": "Perps snapshot activity agreement",
67
+ "intent": "Preserve reviewer-visible proof of the compared activity surface",
68
+ "next": "done"
69
+ },
70
+ "done": {
71
+ "action": "end",
72
+ "status": "pass"
73
+ }
74
+ }
75
+ }
76
+ }
@@ -19,11 +19,25 @@
19
19
  "leverage": {
20
20
  "type": "integer",
21
21
  "minimum": 1,
22
- "default": 3
22
+ "default": 1
23
+ },
24
+ "provider": {
25
+ "type": "string",
26
+ "default": "hyperliquid"
27
+ },
28
+ "network": {
29
+ "type": "string",
30
+ "enum": [
31
+ "mainnet",
32
+ "testnet"
33
+ ],
34
+ "default": "mainnet"
23
35
  },
24
36
  "confirm_live": {
25
37
  "type": "boolean"
26
- }
38
+ },
39
+ "identity_rounding_tolerance_base_units": { "type": "string", "default": "10000" },
40
+ "balance_reconciliation_tolerance_base_units": { "type": "string", "default": "1000000" }
27
41
  }
28
42
  },
29
43
  "workflow": {
@@ -33,15 +47,6 @@
33
47
  "action": "ui.navigate",
34
48
  "page": "perps",
35
49
  "intent": "Show the live Perps home surface",
36
- "next": "assert-clean"
37
- },
38
- "assert-clean": {
39
- "action": "metamask.perps.read_visible_state",
40
- "surface": "home",
41
- "maximum_position_count": 0,
42
- "require_features": ["balance", "market-list"],
43
- "max_items": 150,
44
- "intent": "Prove there is no open position before placing the order",
45
50
  "next": "open-market-list"
46
51
  },
47
52
  "open-market-list": {
@@ -63,8 +68,12 @@
63
68
  "side": "long",
64
69
  "amount": "{{params.amount}}",
65
70
  "leverage": "{{params.leverage}}",
71
+ "provider": "{{params.provider}}",
72
+ "network": "{{params.network}}",
66
73
  "order_type": "market",
67
74
  "confirm_live": "{{params.confirm_live}}",
75
+ "identity_rounding_tolerance_base_units": "{{params.identity_rounding_tolerance_base_units}}",
76
+ "submit_attempts": 1,
68
77
  "timeout_ms": 45000,
69
78
  "intent": "Submit the authorized order exactly once",
70
79
  "next": "wait-position"
@@ -100,14 +109,22 @@
100
109
  "action": "metamask.perps.close_visible_position",
101
110
  "market": "{{params.market}}",
102
111
  "confirm_live": "{{params.confirm_live}}",
112
+ "funding_side": "long",
113
+ "funding_amount": "{{params.amount}}",
114
+ "provider": "{{params.provider}}",
115
+ "network": "{{params.network}}",
116
+ "leverage": "{{params.leverage}}",
117
+ "identity_rounding_tolerance_base_units": "{{params.identity_rounding_tolerance_base_units}}",
118
+ "balance_reconciliation_tolerance_base_units": "{{params.balance_reconciliation_tolerance_base_units}}",
103
119
  "intent": "Close the live position after proving it",
104
120
  "next": "assert-closed"
105
121
  },
106
122
  "assert-closed": {
107
123
  "action": "metamask.perps.read_visible_state",
108
- "surface": "market-details",
109
- "market": "{{params.market}}",
124
+ "surface": "home",
110
125
  "maximum_position_count": 0,
126
+ "maximum_order_count": 0,
127
+ "require_features": ["balance", "market-list"],
111
128
  "minimum_activity_count": 1,
112
129
  "max_items": 150,
113
130
  "intent": "Prove the position was removed and close activity was recorded",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "Perps release market details",
4
- "description": "Opens one live Perps market through visible UI and proves its price, change, statistics, and Long/Short controls without development-only bridges.",
4
+ "description": "Opens one live Perps market through visible UI and proves its header price, change, statistics, and Long/Short controls; it does not assert chart data.",
5
5
  "paramsSchema": {
6
6
  "type": "object",
7
7
  "additionalProperties": false,