@deeeed/metamask-harness 0.94.4 → 0.94.6
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
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.94.6 - 2026-10-28
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Scope receipt-backed Extension testnet closes to their owned market while preserving other markets' positions and orders.
|
|
10
|
+
|
|
11
|
+
## 0.94.5 - 2026-10-28
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Extension readiness uses the registered EVM background action and preserves its result when the optional Perps read times out, keeping genuine RPC failures fatal.
|
|
16
|
+
|
|
5
17
|
## 0.94.4 - 2026-10-27
|
|
6
18
|
|
|
7
19
|
### Changed
|
|
@@ -328,7 +328,7 @@ async function boundedCdpCall(session, method, params, timeoutMs) {
|
|
|
328
328
|
async function evaluateHealth(session, timeoutMs) {
|
|
329
329
|
const backgroundProbeTimeoutMs = extensionBackgroundProbeTimeoutMs(timeoutMs);
|
|
330
330
|
const result = await boundedCdpCall(session, "Runtime.evaluate", {
|
|
331
|
-
expression: `(() => {
|
|
331
|
+
expression: `(async () => {
|
|
332
332
|
const hooks = globalThis.stateHooks || {};
|
|
333
333
|
const bodyText = document.body?.innerText || '';
|
|
334
334
|
const storeState = hooks.store?.getState?.() || {};
|
|
@@ -336,78 +336,80 @@ async function evaluateHealth(session, timeoutMs) {
|
|
|
336
336
|
const accountCache = manager?.account?.cache;
|
|
337
337
|
const networkConnectionBanner = storeState.metamask?.networkConnectionBanner;
|
|
338
338
|
const networkClientId = storeState.metamask?.selectedNetworkClientId || networkConnectionBanner?.networkClientId;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const accountState = await hooks.submitRequestToBackground('perpsGetAccountState', []);
|
|
348
|
-
const ok = Boolean(accountState && typeof accountState === 'object');
|
|
349
|
-
return { ok, error: ok ? null : 'perpsGetAccountState returned an empty result' };
|
|
350
|
-
} catch (error) {
|
|
351
|
-
return { ok: false, error: String(error?.message || error) };
|
|
352
|
-
}
|
|
353
|
-
})(),
|
|
354
|
-
(async () => {
|
|
355
|
-
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
356
|
-
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
357
|
-
}
|
|
358
|
-
if (typeof networkClientId !== 'string' || networkClientId.length === 0) {
|
|
359
|
-
return { ok: false, error: 'selected EVM network client is unavailable' };
|
|
360
|
-
}
|
|
361
|
-
try {
|
|
362
|
-
const code = await hooks.submitRequestToBackground('getCode', [
|
|
363
|
-
'0x0000000000000000000000000000000000000000',
|
|
364
|
-
networkClientId,
|
|
365
|
-
]);
|
|
366
|
-
const ok = typeof code === 'string' && code.startsWith('0x');
|
|
367
|
-
return { ok, error: ok ? null : 'background EVM RPC returned an invalid result' };
|
|
368
|
-
} catch (error) {
|
|
369
|
-
return { ok: false, error: String(error?.message || error) };
|
|
370
|
-
}
|
|
371
|
-
})(),
|
|
339
|
+
async function withDeadline(read, error) {
|
|
340
|
+
let timer;
|
|
341
|
+
try {
|
|
342
|
+
return await Promise.race([
|
|
343
|
+
read,
|
|
344
|
+
new Promise((resolve) => {
|
|
345
|
+
timer = setTimeout(() => resolve({ ok: false, error }), ${backgroundProbeTimeoutMs});
|
|
346
|
+
}),
|
|
372
347
|
]);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
348
|
+
} finally {
|
|
349
|
+
clearTimeout(timer);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const [backgroundProbe, evmRpcProbe] = await Promise.all([
|
|
353
|
+
withDeadline((async () => {
|
|
354
|
+
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
355
|
+
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
const accountState = await hooks.submitRequestToBackground('perpsGetAccountState', []);
|
|
359
|
+
const ok = Boolean(accountState && typeof accountState === 'object');
|
|
360
|
+
return { ok, error: ok ? null : 'perpsGetAccountState returned an empty result' };
|
|
361
|
+
} catch (error) {
|
|
362
|
+
return { ok: false, error: String(error?.message || error) };
|
|
363
|
+
}
|
|
364
|
+
})(), 'perpsGetAccountState timed out after ${backgroundProbeTimeoutMs}ms'),
|
|
365
|
+
withDeadline((async () => {
|
|
366
|
+
if (typeof hooks.submitRequestToBackground !== 'function') {
|
|
367
|
+
return { ok: false, error: 'submitRequestToBackground is not a function' };
|
|
368
|
+
}
|
|
369
|
+
if (typeof networkClientId !== 'string' || networkClientId.length === 0) {
|
|
370
|
+
return { ok: false, error: 'selected EVM network client is unavailable' };
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
const args = ['0x0000000000000000000000000000000000000000', networkClientId];
|
|
374
|
+
let code;
|
|
375
|
+
try {
|
|
376
|
+
code = await hooks.submitRequestToBackground('messengerCall', ['LegacyBackgroundApiService:getCode', args]);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
// Older builds may lack the messenger API or its EVM action.
|
|
379
|
+
const message = String(error?.message || error);
|
|
380
|
+
const missingApi = error?.code === -32601 && message === 'messengerCall not found';
|
|
381
|
+
const missingAction = message.includes('A handler for LegacyBackgroundApiService:getCode has not been registered');
|
|
382
|
+
if (!missingApi && !missingAction) throw error;
|
|
383
|
+
code = await hooks.submitRequestToBackground('getCode', args);
|
|
384
|
+
}
|
|
385
|
+
const ok = typeof code === 'string' && code.startsWith('0x');
|
|
386
|
+
return { ok, error: ok ? null : 'background EVM RPC returned an invalid result' };
|
|
387
|
+
} catch (error) {
|
|
388
|
+
return { ok: false, error: String(error?.message || error) };
|
|
389
|
+
}
|
|
390
|
+
})(), 'background EVM RPC timed out after ${backgroundProbeTimeoutMs}ms'),
|
|
410
391
|
]);
|
|
392
|
+
return {
|
|
393
|
+
href: location.href,
|
|
394
|
+
title: document.title,
|
|
395
|
+
hasPageContent: bodyText.trim().length > 0,
|
|
396
|
+
hookKeys: Object.keys(hooks),
|
|
397
|
+
hasSubmitRequest: typeof hooks.submitRequestToBackground === 'function',
|
|
398
|
+
hasStore: Boolean(hooks.store),
|
|
399
|
+
hasPerpsStreamManager: typeof hooks.getPerpsStreamManager === 'function',
|
|
400
|
+
backgroundUnresponsive: bodyText.includes('Background connection unresponsive') || bodyText.includes('MetaMask had trouble starting'),
|
|
401
|
+
ethereumConnectionUnavailable: bodyText.includes('Unable to connect to Ethereum'),
|
|
402
|
+
activeProvider: storeState.metamask?.activeProvider || null,
|
|
403
|
+
isTestnet: Boolean(storeState.metamask?.isTestnet),
|
|
404
|
+
perpsManagerInitialized: Boolean(manager?.isInitialized?.()),
|
|
405
|
+
positionsCacheIsArray: Array.isArray(manager?.positions?.cache),
|
|
406
|
+
ordersCacheIsArray: Array.isArray(manager?.orders?.cache),
|
|
407
|
+
accountCachePresent: Boolean(accountCache && typeof accountCache === 'object'),
|
|
408
|
+
backgroundProbeOk: backgroundProbe.ok,
|
|
409
|
+
backgroundProbeError: backgroundProbe.error,
|
|
410
|
+
evmRpcProbeOk: evmRpcProbe.ok,
|
|
411
|
+
evmRpcProbeError: evmRpcProbe.error,
|
|
412
|
+
};
|
|
411
413
|
})()`,
|
|
412
414
|
awaitPromise: true,
|
|
413
415
|
returnByValue: true
|
|
@@ -294,7 +294,7 @@ export async function closeVisiblePosition(input) {
|
|
|
294
294
|
roundingToleranceBaseUnits,
|
|
295
295
|
...(cleanupOnly ? { positionSize: fundingPositionSize, cleanupOnly: true } : {}),
|
|
296
296
|
});
|
|
297
|
-
const cleanupMarket =
|
|
297
|
+
const cleanupMarket = identity.network === 'testnet' ? market : null;
|
|
298
298
|
const closeBudget = trustedExternalMutationBudget(input, 'perps-close-position');
|
|
299
299
|
const existingReceipt = await readExternalMutationReceipt(input, identity);
|
|
300
300
|
if (existingReceipt) {
|