@deeeed/metamask-harness 0.47.4 → 0.48.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.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -2
- package/adapters/extension/lib/macos-focus.cjs +2 -2
- package/adapters/extension/live.sh +6 -8
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +1 -0
- package/adapters/shared/ensure-runner-deps.sh +6 -0
- package/dist/adapters/extension/runtime-decision.js +18 -1
- package/dist/adapters/extension/runtime.js +5 -5
- package/dist/adapters/extension/surface.js +1 -0
- package/dist/app-lifecycle.js +3 -1
- package/dist/command-contract.js +2 -0
- package/dist/commands/call.js +1 -8
- package/dist/commands/device-target.js +12 -3
- package/dist/commands/doctor.js +7 -5
- package/dist/commands/fixtures.js +1 -1
- package/dist/commands/launch/index.js +10 -0
- package/dist/commands/manifest.js +3 -1
- package/dist/commands/mobile-device-view.js +13 -3
- package/dist/commands/parse-args.js +2 -0
- package/dist/commands/run-engine.js +29 -4
- package/dist/commands/run.js +1 -1
- package/dist/commands/runtime-launch.js +10 -1
- package/dist/commands/status.js +8 -4
- package/dist/devices.js +31 -9
- package/dist/execution-provenance.js +8 -7
- package/dist/funding-execution-context.js +43 -13
- package/dist/heal-bounds.js +3 -3
- package/dist/live-adapter-contract.js +4 -0
- package/dist/manifest.js +2 -13
- package/dist/mm-harness-cli.js +2 -1
- package/dist/runner.js +14 -3
- package/docs/RECIPES.md +133 -22
- package/docs/RELEASE-QA-CAPABILITY-MAP.md +3 -2
- package/library/actions/core/perps/_controller.mjs +10 -0
- package/library/actions/core/perps/close_orders.mjs +13 -17
- package/library/actions/extension/assets/home-token-identity.mjs +30 -0
- package/library/actions/extension/assets/import_custom_token.mjs +61 -79
- package/library/actions/extension/assets/open_details.mjs +18 -7
- package/library/actions/extension/assets/read_details.mjs +61 -29
- package/library/actions/extension/assets/read_visible_state.mjs +4 -1
- package/library/actions/extension/assets/select_network_scope.mjs +16 -9
- package/library/actions/extension/assets/set_token_visibility.mjs +84 -17
- package/library/actions/extension/assets/verify_sorting.mjs +62 -14
- package/library/actions/extension/networks/add_custom.mjs +19 -17
- package/library/actions/extension/networks/custom_network.mjs +8 -3
- package/library/actions/extension/networks/read_visible_state.mjs +1 -0
- package/library/actions/extension/performance/_navigation-memory.mjs +35 -6
- package/library/actions/extension/performance/compare_idle_navigation_memory.mjs +3 -2
- package/library/actions/extension/performance/measure_detached_dom.mjs +3 -2
- package/library/actions/extension/performance/measure_navigation_memory.mjs +3 -2
- package/library/actions/extension/perps/assert_visible_consistency.mjs +9 -4
- package/library/actions/extension/perps/close_visible_position.mjs +3 -3
- package/library/actions/extension/perps/edit_margin.mjs +1 -1
- package/library/actions/extension/perps/open_balance_action.mjs +16 -7
- package/library/actions/extension/perps/perps.mjs +150 -45
- package/library/actions/extension/perps/read_funds_confirmation.mjs +8 -0
- package/library/actions/extension/perps/read_snapshot.mjs +2 -1
- package/library/actions/extension/perps/read_visible_state.mjs +10 -6
- package/library/actions/extension/perps/search_markets.mjs +7 -2
- package/library/actions/extension/perps/select_activity_filter.mjs +1 -1
- package/library/actions/extension/perps/select_market_filter.mjs +74 -45
- package/library/actions/extension/perps/set_market_favorite.mjs +6 -3
- package/library/actions/extension/perps/state.mjs +1 -0
- package/library/actions/extension/perps/update_position_tpsl.mjs +1 -1
- package/library/actions/extension/perps/visible-mutation-identity.mjs +4 -2
- package/library/actions/extension/platform/cdp.mjs +23 -142
- package/library/actions/extension/swap_bridge/quote-state.mjs +54 -0
- package/library/actions/extension/swap_bridge/read_visible_state.mjs +4 -1
- package/library/actions/extension/swap_bridge/select_assets.mjs +11 -1
- package/library/actions/extension/swap_bridge/set_amount.mjs +10 -8
- package/library/actions/extension/swap_bridge/set_max_amount.mjs +17 -18
- package/library/actions/extension/swap_bridge/set_slippage.mjs +0 -9
- package/library/actions/extension/ui/navigate.mjs +58 -14
- package/library/actions/extension/wallet/lock.mjs +2 -1
- package/library/actions/mobile/assets/import_custom_token.mjs +1 -0
- package/library/actions/mobile/assets/read_visible_state.mjs +3 -1
- package/library/actions/mobile/assets/set_token_visibility.mjs +13 -9
- package/library/actions/mobile/networks/network-management.mjs +22 -15
- package/library/actions/mobile/networks/remove_custom.mjs +6 -2
- package/library/actions/mobile/perps/perps.mjs +3 -0
- package/library/actions/mobile/perps/read-visible-state-loop.mjs +1 -0
- package/library/actions/mobile/perps/set_market_favorite.mjs +15 -19
- package/library/actions/mobile/platform/native-session.mjs +26 -17
- package/library/actions/mobile/platform/observe-ui.mjs +2 -2
- package/library/actions/mobile/ui/navigate.mjs +1 -1
- package/library/actions/shared/perps/visible-state.mjs +14 -3
- package/library/manifests/core.action-manifest.json +14 -2
- package/library/manifests/extension.action-manifest.json +49 -16
- package/library/manifests/mobile.action-manifest.json +8 -7
- package/library/recipes/core/perps/smoke.recipe.json +23 -0
- package/library/recipes/core/perps/snapshot.recipe.json +26 -1
- package/library/recipes/extension/assets/release-custom-network-token-persistence.recipe.json +25 -8
- package/library/recipes/extension/performance/navigation-memory-suite.recipe.json +219 -0
- package/library/recipes/extension/performance/navigation-memory.recipe.json +61 -156
- package/library/recipes/extension/wallet/smoke.recipe.json +17 -8
- package/library/recipes/mobile/app/lifecycle.android-smoke.recipe.json +23 -4
- package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +31 -6
- package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +5 -4
- package/library/recipes/mobile/wallet/smoke.recipe.json +17 -8
- package/library/recipes/{assets → shared/assets}/release-token-address-import.recipe.json +7 -0
- package/library/recipes/{assets → shared/assets}/release-token-details.recipe.json +2 -2
- package/library/recipes/shared/assets/release-token-hide-readd.recipe.json +91 -0
- package/library/recipes/{assets → shared/assets}/release-token-persistence.recipe.json +3 -0
- package/library/recipes/{assets → shared/assets}/release-token-search-import.recipe.json +4 -1
- package/library/recipes/{assets → shared/assets}/release-token-sorting.recipe.json +13 -2
- package/library/recipes/{swap-bridge → shared/swap-bridge}/release-quote.recipe.json +29 -3
- package/package.json +3 -3
- package/site/assets/help-recipes.json +63 -23
- package/library/recipes/assets/release-token-hide-readd.recipe.json +0 -57
- package/library/recipes/core/perps/clean-market-testnet.recipe.json +0 -44
- package/library/recipes/core/perps/order-lifecycle.recipe.json +0 -82
- package/library/recipes/core/perps/read-markets.recipe.json +0 -36
- package/library/recipes/core/perps/trading-lifecycle.recipe.json +0 -80
- package/library/recipes/extension/perps/release-activity-filters.recipe.json +0 -51
- package/library/recipes/extension/perps/release-funds-flows.recipe.json +0 -76
- package/library/recipes/extension/perps/release-live-limit-order.recipe.json +0 -109
- package/library/recipes/extension/perps/release-market-filters.recipe.json +0 -97
- package/library/recipes/extension/perps/release-order-entry.recipe.json +0 -158
- package/library/recipes/extension/perps/release-order-validation.recipe.json +0 -259
- package/library/recipes/extension/perps/release-visible-consistency.recipe.json +0 -47
- package/library/recipes/extension/perps/source-dev-snapshot-consistency.recipe.json +0 -76
- package/library/recipes/mobile/perps/chase-assert-running.recipe.json +0 -110
- package/library/recipes/mobile/perps/chase-place.recipe.json +0 -145
- package/library/recipes/mobile/perps/chase-terminate.recipe.json +0 -98
- package/library/recipes/mobile/perps/performance.recipe.json +0 -722
- package/library/recipes/mobile/perps/pro-order-setup.recipe.json +0 -111
- package/library/recipes/mobile/perps/pro-order-start-state.recipe.json +0 -53
- package/library/recipes/mobile/perps/scale-assert-orders.recipe.json +0 -126
- package/library/recipes/mobile/perps/scale-place.recipe.json +0 -186
- package/library/recipes/mobile/perps/twap-assert-active.recipe.json +0 -97
- package/library/recipes/mobile/perps/twap-place.recipe.json +0 -146
- package/library/recipes/mobile/runner/action-validation.recipe.json +0 -336
- package/library/recipes/perps/clean-market-testnet.recipe.json +0 -49
- package/library/recipes/perps/lifecycle.recipe.json +0 -144
- package/library/recipes/perps/release-live-market-order.recipe.json +0 -139
- package/library/recipes/perps/release-watchlist.recipe.json +0 -111
- package/library/recipes/swap-bridge/release-max-quote.recipe.json +0 -72
- /package/library/recipes/{assets → shared/assets}/release-token-list.recipe.json +0 -0
- /package/library/recipes/{perps → shared/perps}/release-market-details.recipe.json +0 -0
- /package/library/recipes/{perps → shared/perps}/release-market-search.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-custom-slippage.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-max-swap.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-swap.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-surface.recipe.json +0 -0
- /package/library/recipes/{wallet → shared/wallet}/import.recipe.json +0 -0
- /package/library/recipes/{wallet → shared/wallet}/reset-import.recipe.json +0 -0
|
@@ -1,9 +1,38 @@
|
|
|
1
|
+
import { mkdtemp, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
1
4
|
const DEFAULT_SCREEN_TIMEOUT_MS = 15_000;
|
|
2
5
|
const DEFAULT_SETTLE_MS = 1_500;
|
|
3
6
|
const DEFAULT_GC_SETTLE_MS = 300;
|
|
4
7
|
const DEFAULT_ACTION_TIMEOUT_MS = 400_000;
|
|
5
8
|
const DEFAULT_ROUND_DURATION_MS = 10_000;
|
|
6
9
|
|
|
10
|
+
export async function withMemoryFailureReport(input, measure) {
|
|
11
|
+
try {
|
|
12
|
+
return await measure();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
if (!error?.memoryMeasurement) throw error;
|
|
15
|
+
const directory = await mkdtemp(path.join(input.context.artifactsDir, 'navigation-memory-'));
|
|
16
|
+
const report = path.join(directory, 'measurement.json');
|
|
17
|
+
await writeFile(report, `${JSON.stringify({
|
|
18
|
+
nodeId: input.context.nodeId,
|
|
19
|
+
action: input.action,
|
|
20
|
+
...error.memoryMeasurement,
|
|
21
|
+
}, null, 2)}\n`, { mode: 0o600 });
|
|
22
|
+
await writeFile(input.outputPath, `${JSON.stringify({ artifacts: [{
|
|
23
|
+
path: path.relative(input.context.artifactsDir, report),
|
|
24
|
+
type: 'report',
|
|
25
|
+
nodeId: input.context.nodeId,
|
|
26
|
+
label: 'Failed memory measurement',
|
|
27
|
+
category: 'diagnostic',
|
|
28
|
+
mimeType: 'application/json',
|
|
29
|
+
}] })}\n`, { mode: 0o600 });
|
|
30
|
+
delete error.memoryMeasurement;
|
|
31
|
+
error.message += `\nNext: jq . ${JSON.stringify(report)}`;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
7
36
|
function finiteNumber(value, fallback, label) {
|
|
8
37
|
const parsed = value ?? fallback;
|
|
9
38
|
if (!Number.isFinite(parsed)) throw new Error(`${label} must be a finite number.`);
|
|
@@ -217,9 +246,9 @@ export async function measureNavigationSlope(page, options, bounds) {
|
|
|
217
246
|
passed,
|
|
218
247
|
};
|
|
219
248
|
if (!passed.nodes || !passed.listeners) {
|
|
220
|
-
throw new Error(
|
|
249
|
+
throw Object.assign(new Error(
|
|
221
250
|
`Navigation memory bounds exceeded: nodes ${slopes.nodes.toFixed(2)}/${bounds.maxNodesPerCycle} per cycle; listeners ${slopes.listeners.toFixed(2)}/${bounds.maxListenersPerCycle} per cycle.`,
|
|
222
|
-
);
|
|
251
|
+
), { memoryMeasurement: result });
|
|
223
252
|
}
|
|
224
253
|
return result;
|
|
225
254
|
}
|
|
@@ -282,9 +311,9 @@ export async function measureDetachedDom(page, options, maxDetachedGrowth) {
|
|
|
282
311
|
passed: after - before <= maxDetachedGrowth,
|
|
283
312
|
};
|
|
284
313
|
if (!result.passed) {
|
|
285
|
-
throw new Error(
|
|
314
|
+
throw Object.assign(new Error(
|
|
286
315
|
`Detached DOM bound exceeded: growth ${result.growth}/${maxDetachedGrowth} nodes.`,
|
|
287
|
-
);
|
|
316
|
+
), { memoryMeasurement: result });
|
|
288
317
|
}
|
|
289
318
|
return result;
|
|
290
319
|
}
|
|
@@ -333,9 +362,9 @@ export async function compareIdleNavigation(page, options, maxAttributableListen
|
|
|
333
362
|
passed: attributableListenersPerCycle <= maxAttributableListenersPerCycle,
|
|
334
363
|
};
|
|
335
364
|
if (!result.passed) {
|
|
336
|
-
throw new Error(
|
|
365
|
+
throw Object.assign(new Error(
|
|
337
366
|
`Idle-control bound exceeded: attributable listeners ${attributableListenersPerCycle.toFixed(2)}/${maxAttributableListenersPerCycle} per cycle (navigation ${navigation.slopes.listeners.toFixed(2)}, idle ${idleListenersPerCycle.toFixed(2)}).`,
|
|
338
|
-
);
|
|
367
|
+
), { memoryMeasurement: result });
|
|
339
368
|
}
|
|
340
369
|
return result;
|
|
341
370
|
}
|
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
compareIdleNavigation,
|
|
4
4
|
idleControlBound,
|
|
5
5
|
navigationMemoryOptions,
|
|
6
|
+
withMemoryFailureReport,
|
|
6
7
|
} from './_navigation-memory.mjs';
|
|
7
8
|
|
|
8
9
|
runAdapter((input) =>
|
|
9
|
-
withExtensionPage(input, async (page) => ({
|
|
10
|
+
withMemoryFailureReport(input, () => withExtensionPage(input, async (page) => ({
|
|
10
11
|
action: input.action,
|
|
11
12
|
status: 'pass',
|
|
12
13
|
...(await compareIdleNavigation(
|
|
@@ -14,5 +15,5 @@ runAdapter((input) =>
|
|
|
14
15
|
navigationMemoryOptions(input.node, 'rounds', 8),
|
|
15
16
|
idleControlBound(input.node),
|
|
16
17
|
)),
|
|
17
|
-
})),
|
|
18
|
+
}))),
|
|
18
19
|
);
|
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
detachedDomBound,
|
|
4
4
|
measureDetachedDom,
|
|
5
5
|
navigationMemoryOptions,
|
|
6
|
+
withMemoryFailureReport,
|
|
6
7
|
} from './_navigation-memory.mjs';
|
|
7
8
|
|
|
8
9
|
runAdapter((input) =>
|
|
9
|
-
withExtensionPage(input, async (page) => ({
|
|
10
|
+
withMemoryFailureReport(input, () => withExtensionPage(input, async (page) => ({
|
|
10
11
|
action: input.action,
|
|
11
12
|
status: 'pass',
|
|
12
13
|
...(await measureDetachedDom(
|
|
@@ -14,5 +15,5 @@ runAdapter((input) =>
|
|
|
14
15
|
navigationMemoryOptions(input.node, 'cycles', 5),
|
|
15
16
|
detachedDomBound(input.node),
|
|
16
17
|
)),
|
|
17
|
-
})),
|
|
18
|
+
}))),
|
|
18
19
|
);
|
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
measureNavigationSlope,
|
|
4
4
|
navigationMemoryOptions,
|
|
5
5
|
navigationSlopeBounds,
|
|
6
|
+
withMemoryFailureReport,
|
|
6
7
|
} from './_navigation-memory.mjs';
|
|
7
8
|
|
|
8
9
|
runAdapter((input) =>
|
|
9
|
-
withExtensionPage(input, async (page) => ({
|
|
10
|
+
withMemoryFailureReport(input, () => withExtensionPage(input, async (page) => ({
|
|
10
11
|
action: input.action,
|
|
11
12
|
status: 'pass',
|
|
12
13
|
...(await measureNavigationSlope(
|
|
@@ -14,5 +15,5 @@ runAdapter((input) =>
|
|
|
14
15
|
navigationMemoryOptions(input.node),
|
|
15
16
|
navigationSlopeBounds(input.node),
|
|
16
17
|
)),
|
|
17
|
-
})),
|
|
18
|
+
}))),
|
|
18
19
|
);
|
|
@@ -86,7 +86,8 @@ async function visiblePrice(page, surface, market) {
|
|
|
86
86
|
if (!element) return false;
|
|
87
87
|
const style = getComputedStyle(element);
|
|
88
88
|
const rect = element.getBoundingClientRect();
|
|
89
|
-
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
89
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
90
|
+
&& rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth;
|
|
90
91
|
};
|
|
91
92
|
const root = document.querySelector('[data-testid=${JSON.stringify(rootTestId)}]');
|
|
92
93
|
const price = ${priceTestId
|
|
@@ -111,7 +112,8 @@ async function marketRows(page, maxItems) {
|
|
|
111
112
|
if (testId.startsWith('market-row-ticker-') || /-(?:token-logo|asset-label)$/u.test(testId)) return false;
|
|
112
113
|
const style = getComputedStyle(element);
|
|
113
114
|
const rect = element.getBoundingClientRect();
|
|
114
|
-
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
115
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
116
|
+
&& rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth;
|
|
115
117
|
}).slice(0, ${JSON.stringify(maxItems)}).map((element) => ({
|
|
116
118
|
testId: String(element.getAttribute('data-testid') || '').slice(0, 500),
|
|
117
119
|
label: String(element.innerText || '').replace(/\\s+/gu, ' ').trim().slice(0, 500),
|
|
@@ -124,7 +126,8 @@ async function watchlistRows(page, maxItems) {
|
|
|
124
126
|
].filter((element) => {
|
|
125
127
|
const style = getComputedStyle(element);
|
|
126
128
|
const rect = element.getBoundingClientRect();
|
|
127
|
-
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
129
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
130
|
+
&& rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth;
|
|
128
131
|
}).slice(0, ${JSON.stringify(maxItems)}).map((element) => ({
|
|
129
132
|
testId: String(element.getAttribute('data-testid') || '').slice(0, 500),
|
|
130
133
|
label: String(element.innerText || '').replace(/\\s+/gu, ' ').trim().slice(0, 500),
|
|
@@ -138,6 +141,7 @@ function changedRows(first, last) {
|
|
|
138
141
|
.map((entry) => entry.testId);
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
// Containment checks loaded full-list rows, including rows below the viewport.
|
|
141
145
|
async function activityIds(page, maxItems) {
|
|
142
146
|
const selector = '[data-testid^="transaction-card-"]';
|
|
143
147
|
return page.evaluate(`[
|
|
@@ -155,7 +159,8 @@ async function recentActivityState(page, maxItems) {
|
|
|
155
159
|
if (!element) return false;
|
|
156
160
|
const style = getComputedStyle(element);
|
|
157
161
|
const rect = element.getBoundingClientRect();
|
|
158
|
-
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
162
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
163
|
+
&& rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth;
|
|
159
164
|
};
|
|
160
165
|
return {
|
|
161
166
|
ids: [...document.querySelectorAll('[data-testid^="transaction-card-"]')]
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
trustedExternalMutationPlanIsExact,
|
|
11
11
|
withExternalMutationRecovery,
|
|
12
12
|
} from './mutation-receipt.mjs';
|
|
13
|
-
import { requireCurrentVisibleFundingBalance, requirePerpsTradingContext } from './perps.mjs';
|
|
13
|
+
import { placementReceiptSelection, requireCurrentVisibleFundingBalance, requirePerpsTradingContext } from './perps.mjs';
|
|
14
14
|
import {
|
|
15
15
|
absoluteDelta,
|
|
16
16
|
parsePositionDetail,
|
|
@@ -281,7 +281,7 @@ export async function closeVisiblePosition(input) {
|
|
|
281
281
|
throw new Error('Visible Perps position notional is unavailable or exceeds the authorized close cap.');
|
|
282
282
|
}
|
|
283
283
|
if (!cleanupOnly) {
|
|
284
|
-
await readPriorMutationReceipt(input, identity, 'metamask.perps.place_order');
|
|
284
|
+
await readPriorMutationReceipt(input, identity, 'metamask.perps.place_order', placementReceiptSelection(input));
|
|
285
285
|
}
|
|
286
286
|
const balanceBeforeBaseUnits = fundingBalance.observedBaseUnits;
|
|
287
287
|
if (!/^(?:0|[1-9][0-9]{0,29})$/u.test(balanceBeforeBaseUnits)) {
|
|
@@ -303,7 +303,6 @@ export async function closeVisiblePosition(input) {
|
|
|
303
303
|
let dispatchTarget;
|
|
304
304
|
try {
|
|
305
305
|
await requireCurrentVisibleFundingBalance(input, page, timeoutMs, fundingBalance.observedBaseUnits);
|
|
306
|
-
await requirePerpsTradingContext(input, page);
|
|
307
306
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
308
307
|
const current = await readVisibleClosePosition(page, market);
|
|
309
308
|
const currentPosition = parsePositionDetail({ pair: `${market}-USD`, ...current });
|
|
@@ -322,6 +321,7 @@ export async function closeVisiblePosition(input) {
|
|
|
322
321
|
const rect = element.getBoundingClientRect();
|
|
323
322
|
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
|
324
323
|
})()`);
|
|
324
|
+
await requirePerpsTradingContext(input, page);
|
|
325
325
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
326
326
|
} catch (error) {
|
|
327
327
|
throw externalMutationNotDispatched(error instanceof Error ? error.message : String(error));
|
|
@@ -266,7 +266,6 @@ export async function editMargin(input) {
|
|
|
266
266
|
let dispatchTarget;
|
|
267
267
|
try {
|
|
268
268
|
await requireCurrentVisibleFundingBalance(input, page, timeoutMs, fundingBalance.observedBaseUnits);
|
|
269
|
-
await requirePerpsTradingContext(input, page);
|
|
270
269
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
271
270
|
const current = await readPosition(page, market);
|
|
272
271
|
if (current.marginBaseUnits !== before.marginBaseUnits || current.size !== before.size
|
|
@@ -284,6 +283,7 @@ export async function editMargin(input) {
|
|
|
284
283
|
const rect = element.getBoundingClientRect();
|
|
285
284
|
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
|
286
285
|
})()`);
|
|
286
|
+
await requirePerpsTradingContext(input, page);
|
|
287
287
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
288
288
|
} catch (error) {
|
|
289
289
|
throw externalMutationNotDispatched(error instanceof Error ? error.message : String(error));
|
|
@@ -11,13 +11,22 @@ runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
|
11
11
|
if (!actionTestId) {
|
|
12
12
|
throw new Error(`metamask.perps.open_balance_action received unsupported balance_action ${JSON.stringify(balanceAction)}.`);
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
14
|
+
const directSelector = dataTestId(`perps-balance-actions-${balanceAction}`);
|
|
15
|
+
const directVisible = await page.evaluate(`(() => {
|
|
16
|
+
const element = document.querySelector(${JSON.stringify(directSelector)});
|
|
17
|
+
if (!element) return false;
|
|
18
|
+
const style = getComputedStyle(element), rect = element.getBoundingClientRect();
|
|
19
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0;
|
|
20
|
+
})()`);
|
|
21
|
+
const actionSelector = directVisible ? directSelector : dataTestId(actionTestId);
|
|
22
|
+
if (!directVisible) {
|
|
23
|
+
await page.click(dataTestId('perps-balance-dropdown-balance'));
|
|
24
|
+
await page.waitForSelector(actionSelector, { timeoutMs: 10_000 });
|
|
25
|
+
}
|
|
17
26
|
await page.click(actionSelector);
|
|
18
27
|
const expected = balanceAction === 'withdraw'
|
|
19
|
-
? ['perps-withdraw-page', 'perps-withdraw-container', 'perps-withdraw-view']
|
|
20
|
-
: ['confirm-page-container-content', 'confirm-page-container', 'transaction-confirmation'];
|
|
28
|
+
? ['parent-selector-perps-withdraw', 'parent-selector-confirmation-page', 'perps-withdraw-page', 'perps-withdraw-container', 'perps-withdraw-view']
|
|
29
|
+
: ['parent-selector-confirmation-page', 'confirm-page-container-content', 'confirm-page-container', 'transaction-confirmation'];
|
|
21
30
|
const resultDeadline = Date.now() + 15_000;
|
|
22
31
|
let observed;
|
|
23
32
|
while (Date.now() <= resultDeadline) {
|
|
@@ -38,10 +47,10 @@ runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
|
38
47
|
text: String(document.body?.innerText || '').replace(/\\s+/gu, ' ').trim().slice(0, 10_000),
|
|
39
48
|
};
|
|
40
49
|
})()`);
|
|
41
|
-
if (observed.matched.length > 0
|
|
50
|
+
if (observed.matched.length > 0) break;
|
|
42
51
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
43
52
|
}
|
|
44
|
-
if (!observed ||
|
|
53
|
+
if (!observed || observed.matched.length === 0) {
|
|
45
54
|
throw new Error(`Perps ${balanceAction} did not open: ${JSON.stringify(observed)}.`);
|
|
46
55
|
}
|
|
47
56
|
return {
|