@deeeed/metamask-harness 0.79.0 → 0.81.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 +73 -0
- package/README.md +1 -1
- package/adapters/extension/ensure-browser.sh +2 -2
- package/adapters/extension/inject.mjs +0 -1
- package/adapters/extension/launch-browser.cjs +39 -613
- package/adapters/extension/readiness.mjs +2 -5
- package/adapters/extension/reattach.sh +2 -2
- package/adapters/extension/stamp-runtime-title.cjs +1 -1
- package/adapters/manifest.json +16 -64
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
- package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
- package/adapters/mobile/inject.sh +16 -0
- package/adapters/mobile/launch-console-forwarder.cjs +1 -2
- package/adapters/mobile/open-device.sh +2 -2
- package/adapters/mobile/reload-app.mjs +4 -4
- package/adapters/mobile/reset-app-data.sh +1 -1
- package/adapters/mobile/start-console-forwarder.sh +3 -2
- package/adapters/mobile/start-metro.sh +17 -12
- package/adapters/mobile/wait-for-bridge.cjs +2 -2
- package/adapters/shared/harness-source-fingerprint.mjs +13 -8
- package/adapters/shared/open-debug.mjs +2 -2
- package/adapters/shared/sync-wallet-fixture.sh +8 -5
- package/adapters/terminal/cleanup.mjs +2 -1
- package/adapters/terminal/inject.mjs +2 -1
- package/adapters/terminal/launch.mjs +17 -13
- package/adapters/terminal/lib/mainnet-guard.mjs +9 -0
- package/adapters/terminal/lib/readiness.mjs +20 -12
- package/adapters/terminal/policy.mjs +35 -0
- package/adapters/terminal/verify.mjs +10 -3
- package/adapters/terminal/wallet-host.mjs +43 -225
- package/bin/mm-harness +9 -28
- package/dist/adapters/checkout-files.js +16 -0
- package/dist/adapters/console-capture.js +14 -1
- package/dist/adapters/core/actions.js +8 -4
- package/dist/adapters/core/overlay.js +1 -1
- package/dist/adapters/core/readiness.js +28 -1
- package/dist/adapters/core/run.js +2 -2
- package/dist/adapters/core/surface.js +16 -1
- package/dist/adapters/extension/actions.js +6 -2
- package/dist/adapters/extension/browser-pid.js +56 -0
- package/dist/adapters/extension/console-capture.js +1 -1
- package/dist/adapters/extension/doctor-checks.js +1 -1
- package/dist/adapters/extension/ensure-ready.js +5 -4
- package/dist/adapters/extension/extension-id.js +1 -1
- package/dist/adapters/extension/feature-flags.js +1 -1
- package/dist/adapters/extension/fixtures.js +1 -2
- package/dist/adapters/extension/launch.js +4 -5
- package/dist/adapters/extension/launched-browser.js +1 -2
- package/dist/adapters/extension/network-observer.js +14 -1
- package/dist/adapters/extension/overlay.js +1 -1
- package/dist/adapters/extension/product-config.js +1 -1
- package/dist/adapters/extension/readiness.js +1 -1
- package/dist/adapters/extension/reload.js +1 -1
- package/dist/adapters/extension/run.js +135 -14
- package/dist/adapters/extension/runtime-decision.js +2 -1
- package/dist/adapters/extension/runtime.js +9 -5
- package/dist/adapters/extension/surface.js +15 -2
- package/dist/adapters/extension/verify.js +2 -2
- package/dist/adapters/harness-freshness.js +2 -1
- package/dist/adapters/mobile/actions.js +4 -1
- package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
- package/dist/adapters/mobile/app-identity.js +10 -0
- package/dist/adapters/mobile/doctor-checks.js +1 -1
- package/dist/adapters/mobile/fixtures.js +1 -1
- package/dist/adapters/mobile/launch.js +27 -28
- package/dist/adapters/mobile/lifecycle.js +1 -1
- package/dist/adapters/mobile/metro-env.js +9 -59
- package/dist/adapters/mobile/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +2 -4
- package/dist/adapters/mobile/prepare-target.js +1 -1
- package/dist/adapters/mobile/prepare.js +3 -4
- package/dist/adapters/mobile/provision.js +1 -1
- package/dist/adapters/mobile/readiness.js +1 -1
- package/dist/adapters/mobile/recording-target.js +15 -0
- package/dist/adapters/mobile/release-artifact-state.js +1 -1
- package/dist/adapters/mobile/reload.js +1 -1
- package/dist/adapters/mobile/run.js +39 -15
- package/dist/adapters/mobile/runtime-decision.js +2 -4
- package/dist/adapters/mobile/source-freshness.js +22 -126
- package/dist/adapters/mobile/surface.js +26 -3
- package/dist/adapters/mobile/ui.js +16 -5
- package/dist/adapters/mobile/verify.js +2 -3
- package/dist/adapters/performance/cdp-trace.js +1 -1
- package/dist/adapters/performance/device-platform.js +1 -1
- package/dist/adapters/perps-order-inputs.js +36 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/slot-ports.js +1 -1
- package/dist/adapters/surface.js +1 -0
- package/dist/adapters/terminal/actions.js +4 -1
- package/dist/adapters/terminal/console-capture.js +1 -1
- package/dist/adapters/terminal/doctor-checks.js +2 -0
- package/dist/adapters/terminal/launch.js +4 -1
- package/dist/adapters/terminal/overlay.js +8 -1
- package/dist/adapters/terminal/run.js +33 -5
- package/dist/adapters/terminal/surface.js +9 -1
- package/dist/adapters.js +27 -7
- package/dist/advisor-policy.js +1 -1
- package/dist/checkout-view.js +1 -2
- package/dist/cli.js +59 -21
- package/dist/command-contract.js +1 -26
- package/dist/commands/check.js +33 -10
- package/dist/commands/checklist.js +1 -1
- package/dist/commands/completion-candidates.js +6 -14
- package/dist/commands/config.js +2 -2
- package/dist/commands/core-readiness.js +12 -7
- package/dist/commands/debug.js +3 -3
- package/dist/commands/device-target.js +5 -5
- package/dist/commands/doctor.js +2 -14
- package/dist/commands/domain.js +2 -2
- package/dist/commands/ensure-ready.js +1 -7
- package/dist/commands/fixtures.js +5 -6
- package/dist/commands/help.js +3 -4
- package/dist/commands/launch/device.js +10 -17
- package/dist/commands/launch/extension.js +2 -8
- package/dist/commands/launch/mobile.js +1 -1
- package/dist/commands/logs.js +3 -3
- package/dist/commands/mobile-device-view.js +4 -2
- package/dist/commands/overlay.js +110 -0
- package/dist/commands/pin.js +1 -1
- package/dist/commands/pr-body.js +2 -2
- package/dist/commands/prepare.js +4 -9
- package/dist/commands/provision.js +3 -12
- package/dist/commands/recipe-advice.js +1 -2
- package/dist/commands/recipe-quality.js +2 -3
- package/dist/commands/resolve-extension.js +1 -7
- package/dist/commands/review.js +4 -4
- package/dist/commands/runtime-decision.js +1 -6
- package/dist/commands/runtime-health.js +1 -7
- package/dist/commands/runtime-launch.js +1 -13
- package/dist/commands/self-test.js +5 -8
- package/dist/commands/status-watch.js +1 -2
- package/dist/commands/status.js +2 -5
- package/dist/commands/task-init.js +2 -3
- package/dist/commands/tutorial.js +2 -2
- package/dist/commands/update.js +1 -1
- package/dist/completions-cache.js +1 -1
- package/dist/console-classifier.js +19 -0
- package/dist/doctor.js +2 -3
- package/dist/engine.js +57 -0
- package/dist/funding-execution-context.js +96 -1
- package/dist/host.js +32 -0
- package/dist/index.js +1 -6
- package/dist/live-tsx.js +49 -0
- package/dist/mm-harness-cli.js +4 -6
- package/dist/paths.js +34 -64
- package/dist/performance-observation.js +3 -5
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +6 -9
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +2 -2
- package/dist/runner.js +7 -4
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +2 -3
- package/docs/CONTRIBUTING.md +5 -3
- package/docs/RECIPES.md +31 -3
- package/docs/cli-contract.md +2 -2
- package/docs/feature-guard.md +90 -0
- package/library/README.md +3 -1
- package/library/actions/core/perps/_controller.mjs +153 -134
- package/library/actions/core/perps/_rewards.mjs +186 -0
- package/library/actions/core/perps/close_positions.mjs +1 -1
- package/library/actions/core/perps/place_order.mjs +167 -45
- package/library/actions/core/perps/quote_fees.mjs +61 -0
- package/library/actions/core/wallet/list_accounts.mjs +14 -57
- package/library/actions/extension/feature_flags/state.mjs +1 -1
- package/library/actions/extension/perps/close_visible_position.mjs +5 -0
- package/library/actions/extension/perps/edit_margin.mjs +4 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
- package/library/actions/extension/perps/perps.mjs +320 -3
- package/library/actions/extension/perps/place_order.mjs +3 -1
- package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
- package/library/actions/extension/platform/cdp.mjs +73 -11
- package/library/actions/harness-exports.mjs +1 -6
- package/library/actions/mobile/app/network-control.mjs +6 -8
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
- package/library/actions/mobile/platform/bridge.mjs +8 -8
- package/library/actions/mobile/platform/native-session-name.mjs +21 -1
- package/library/actions/mobile/platform/native-session.mjs +3 -4
- package/library/actions/mobile/platform/observe-ui.mjs +12 -6
- package/library/actions/mobile/ui/native-navigation.mjs +4 -3
- package/library/actions/mobile/wallet/native-ui.mjs +3 -2
- package/library/actions/shared/analytics/_adapter.mjs +1 -1
- package/library/actions/shared/console-findings.mjs +1 -1
- package/library/actions/shared/perps/order-policy.mjs +177 -0
- package/library/actions/shared/wallet/fixture-accounts.mjs +84 -0
- package/library/actions/terminal/app/launch.mjs +3 -2
- package/library/actions/terminal/platform/hud.mjs +2 -1
- package/library/actions/terminal/platform/page.mjs +2 -1
- package/library/actions/terminal/platform/runtime.mjs +2 -1
- package/library/actions/terminal/wallet/_signature-log.mjs +40 -161
- package/library/actions/terminal/wallet/assert_signatures.mjs +6 -12
- package/library/actions/terminal/wallet/read_signatures.mjs +10 -9
- package/library/manifests/core.action-manifest.json +87 -13
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/package.json +8 -9
- package/site/assets/help-recipes.json +1 -0
- package/adapters/extension/lib/slot-title.cjs +0 -292
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
- package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
- package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
- package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
- package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
- package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
- package/adapters/mobile/coalesce-metro-log.cjs +0 -24
- package/adapters/mobile/launch-metro.cjs +0 -77
- package/adapters/mobile/metro-config.cjs +0 -98
- package/adapters/mobile/metro-log-generation.cjs +0 -106
- package/adapters/terminal/lib/origin.mjs +0 -30
- package/adapters/terminal/lib/page-script.mjs +0 -246
- package/adapters/terminal/lib/strict-wallet.mjs +0 -138
- package/dist/adapters/mobile/frame-metrics.js +0 -118
- package/dist/adapters/mobile/video-recorder.js +0 -289
- package/dist/artifact-files.js +0 -92
- package/dist/checkout-lock.js +0 -149
- package/dist/cli-color.js +0 -98
- package/dist/command-journal.js +0 -308
- package/dist/commands/call.js +0 -685
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/list-executables.js +0 -247
- package/dist/commands/manifest.js +0 -488
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-engine.js +0 -1340
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/run.js +0 -751
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/discovery.js +0 -15
- package/dist/execution-provenance.js +0 -332
- package/dist/harness.js +0 -451
- package/dist/heal-bounds.js +0 -137
- package/dist/json-stream.js +0 -60
- package/dist/leaf-invoke.js +0 -19
- package/dist/library-provenance.js +0 -33
- package/dist/live-adapter-contract.js +0 -380
- package/dist/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- package/dist/recording-target.js +0 -120
- package/dist/run-diagnostics.js +0 -364
- package/dist/run-recording.js +0 -481
- package/dist/runtime-proof.js +0 -90
- package/library/actions/mobile/platform/tool-paths.mjs +0 -123
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const { createRequire } = require('node:module');
|
|
5
|
-
const path = require('node:path');
|
|
6
|
-
const { pathToFileURL } = require('node:url');
|
|
7
|
-
|
|
8
|
-
function escapeRegExp(value) {
|
|
9
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function appendBlockList(blockList, pattern) {
|
|
13
|
-
if (Array.isArray(blockList)) return [...blockList, pattern];
|
|
14
|
-
return blockList instanceof RegExp ? [blockList, pattern] : [pattern];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function blockListFlags(blockList) {
|
|
18
|
-
const first = Array.isArray(blockList) ? blockList[0] : blockList;
|
|
19
|
-
return first instanceof RegExp && first.ignoreCase ? 'i' : '';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function resolveExpoConfigLoader(projectRoot) {
|
|
23
|
-
const requireFromProject = createRequire(path.join(projectRoot, 'package.json'));
|
|
24
|
-
let requireUtilsPath;
|
|
25
|
-
try {
|
|
26
|
-
requireUtilsPath = requireFromProject.resolve('@expo/require-utils');
|
|
27
|
-
} catch (error) {
|
|
28
|
-
if (error?.code !== 'MODULE_NOT_FOUND') throw error;
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
const { loadModuleSync } = requireFromProject(requireUtilsPath);
|
|
32
|
-
return typeof loadModuleSync === 'function' ? loadModuleSync : null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async function loadProductConfig(configPath, baseConfig, projectRoot) {
|
|
36
|
-
let loaded;
|
|
37
|
-
const expoConfigLoader = resolveExpoConfigLoader(projectRoot);
|
|
38
|
-
if (expoConfigLoader) {
|
|
39
|
-
loaded = expoConfigLoader(configPath);
|
|
40
|
-
} else {
|
|
41
|
-
try {
|
|
42
|
-
loaded = require(configPath);
|
|
43
|
-
} catch (error) {
|
|
44
|
-
if (error?.code !== 'ERR_REQUIRE_ESM') throw error;
|
|
45
|
-
loaded = await import(pathToFileURL(configPath).href);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const moduleValue = await loaded;
|
|
50
|
-
const exported =
|
|
51
|
-
moduleValue?.__esModule || moduleValue?.[Symbol.toStringTag] === 'Module'
|
|
52
|
-
? moduleValue.default
|
|
53
|
-
: moduleValue;
|
|
54
|
-
const config = await exported;
|
|
55
|
-
return typeof config === 'function' ? config(baseConfig) : config;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = async function harnessMetroConfig(baseConfig) {
|
|
59
|
-
const projectRoot = path.resolve(
|
|
60
|
-
process.env.MM_HARNESS_METRO_PROJECT_ROOT || process.cwd(),
|
|
61
|
-
);
|
|
62
|
-
const productConfigPath = path.resolve(
|
|
63
|
-
process.env.MM_HARNESS_METRO_BASE_CONFIG ||
|
|
64
|
-
path.join(projectRoot, 'metro.config.js'),
|
|
65
|
-
);
|
|
66
|
-
if (productConfigPath === __filename) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
'MM_HARNESS_METRO_BASE_CONFIG must reference the product Metro config, not the harness wrapper.',
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
let productConfig = baseConfig;
|
|
72
|
-
if (fs.existsSync(productConfigPath)) {
|
|
73
|
-
productConfig = await loadProductConfig(
|
|
74
|
-
productConfigPath,
|
|
75
|
-
baseConfig,
|
|
76
|
-
projectRoot,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const tempRoot = path.join(projectRoot, 'temp');
|
|
81
|
-
const existingBlockList =
|
|
82
|
-
productConfig.resolver?.blockList ?? baseConfig.resolver?.blockList;
|
|
83
|
-
const tempPattern = new RegExp(
|
|
84
|
-
`^${escapeRegExp(tempRoot)}(?:${escapeRegExp(path.sep)}|$)`,
|
|
85
|
-
blockListFlags(existingBlockList),
|
|
86
|
-
);
|
|
87
|
-
// Inline environment values affect transformed JavaScript. Keep separate
|
|
88
|
-
// cache generations for those inputs instead of deleting the shared cache.
|
|
89
|
-
const envFingerprint = process.env.MM_HARNESS_METRO_ENV_FINGERPRINT;
|
|
90
|
-
return {
|
|
91
|
-
...productConfig,
|
|
92
|
-
...(envFingerprint ? { cacheVersion: `${productConfig.cacheVersion ?? ''}:mm-env:${envFingerprint}` } : {}),
|
|
93
|
-
resolver: {
|
|
94
|
-
...productConfig.resolver,
|
|
95
|
-
blockList: appendBlockList(existingBlockList, tempPattern),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
};
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const crypto = require('node:crypto');
|
|
5
|
-
const fs = require('node:fs');
|
|
6
|
-
const path = require('node:path');
|
|
7
|
-
|
|
8
|
-
const generationIdPattern = /^[A-Za-z0-9-]+$/u;
|
|
9
|
-
|
|
10
|
-
function archiveGenerationId(name) {
|
|
11
|
-
if (!name.startsWith('metro.') || !name.endsWith('.log')) return null;
|
|
12
|
-
const generationId = name.slice('metro.'.length, -'.log'.length);
|
|
13
|
-
return generationIdPattern.test(generationId) ? generationId : null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function positiveInteger(name, fallback) {
|
|
17
|
-
const raw = process.env[name];
|
|
18
|
-
if (raw === undefined || raw === '') return fallback;
|
|
19
|
-
if (!/^[1-9][0-9]*$/u.test(raw)) throw new Error(`${name} must be a positive integer`);
|
|
20
|
-
return Number(raw);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function main() {
|
|
24
|
-
const runtimeArg = process.argv[2];
|
|
25
|
-
const port = process.argv[3];
|
|
26
|
-
const reason = process.argv[4];
|
|
27
|
-
if (!runtimeArg || !/^[1-9][0-9]*$/u.test(port ?? '') || !reason) {
|
|
28
|
-
throw new Error('usage: metro-log-generation.cjs <runtime-dir> <port> <reason>');
|
|
29
|
-
}
|
|
30
|
-
const runtimeDir = fs.realpathSync(runtimeArg);
|
|
31
|
-
const activeLog = path.join(runtimeDir, 'metro.log');
|
|
32
|
-
const evidenceFile = path.join(runtimeDir, 'metro-generation.json');
|
|
33
|
-
const maxArchives = positiveInteger('MM_HARNESS_METRO_LOG_ARCHIVE_COUNT', 4);
|
|
34
|
-
const maxArchiveBytes = positiveInteger('MM_HARNESS_METRO_LOG_ARCHIVE_BYTES', 8 * 1024 * 1024);
|
|
35
|
-
const generationId = `${new Date().toISOString().replace(/[-:.]/gu, '')}-${port}-${process.pid}-${crypto.randomBytes(4).toString('hex')}`;
|
|
36
|
-
if (!generationIdPattern.test(generationId)) throw new Error('generated Metro log identity is invalid');
|
|
37
|
-
let rotatedLog = null;
|
|
38
|
-
|
|
39
|
-
rotatedLog = path.join(runtimeDir, `metro.${generationId}.log`);
|
|
40
|
-
try {
|
|
41
|
-
fs.renameSync(activeLog, rotatedLog);
|
|
42
|
-
const stat = fs.lstatSync(rotatedLog);
|
|
43
|
-
if (!stat.isFile()) {
|
|
44
|
-
fs.renameSync(rotatedLog, activeLog);
|
|
45
|
-
throw new Error('metro.log must be a regular file');
|
|
46
|
-
}
|
|
47
|
-
} catch (error) {
|
|
48
|
-
if (error && error.code === 'ENOENT') rotatedLog = null;
|
|
49
|
-
else throw error;
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
fs.closeSync(fs.openSync(activeLog, 'wx', 0o600));
|
|
53
|
-
} catch (error) {
|
|
54
|
-
if (error && error.code === 'EEXIST') throw new Error('another Metro generation recreated metro.log; refusing to truncate it');
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const archives = fs.readdirSync(runtimeDir)
|
|
59
|
-
.filter((name) => archiveGenerationId(name) !== null)
|
|
60
|
-
.map((name) => {
|
|
61
|
-
const file = path.join(runtimeDir, name);
|
|
62
|
-
const stat = fs.lstatSync(file);
|
|
63
|
-
if (!stat.isFile()) return null;
|
|
64
|
-
return { file, size: stat.size, mtimeMs: stat.mtimeMs };
|
|
65
|
-
})
|
|
66
|
-
.filter(Boolean)
|
|
67
|
-
.sort((left, right) => right.mtimeMs - left.mtimeMs || right.file.localeCompare(left.file));
|
|
68
|
-
|
|
69
|
-
let retainedBytes = 0;
|
|
70
|
-
let retainedCount = 0;
|
|
71
|
-
const retained = [];
|
|
72
|
-
const removed = [];
|
|
73
|
-
for (const archive of archives) {
|
|
74
|
-
if (retainedCount < maxArchives && retainedBytes + archive.size <= maxArchiveBytes) {
|
|
75
|
-
retained.push(archive.file);
|
|
76
|
-
retainedCount += 1;
|
|
77
|
-
retainedBytes += archive.size;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
fs.unlinkSync(archive.file);
|
|
81
|
-
removed.push({ path: archive.file, size: archive.size, reason: retainedCount >= maxArchives ? 'count-limit' : 'size-limit' });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const evidence = {
|
|
85
|
-
schemaVersion: 1,
|
|
86
|
-
generationId,
|
|
87
|
-
port: Number(port),
|
|
88
|
-
startedAt: new Date().toISOString(),
|
|
89
|
-
currentLog: activeLog,
|
|
90
|
-
rotatedLog: rotatedLog && fs.existsSync(rotatedLog) ? rotatedLog : null,
|
|
91
|
-
archivedLogs: retained,
|
|
92
|
-
rotationReason: reason,
|
|
93
|
-
retention: { maxArchives, maxArchiveBytes, retainedBytes, removed },
|
|
94
|
-
};
|
|
95
|
-
const temporary = `${evidenceFile}.${process.pid}.tmp`;
|
|
96
|
-
fs.writeFileSync(temporary, `${JSON.stringify(evidence, null, 2)}\n`, { mode: 0o600, flag: 'wx' });
|
|
97
|
-
fs.renameSync(temporary, evidenceFile);
|
|
98
|
-
process.stdout.write(`${JSON.stringify(evidence)}\n`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
main();
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error(`metro-log-generation: ${error instanceof Error ? error.message : String(error)}`);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Exact app-origin checks for the terminal slot. A prefix match would let
|
|
2
|
-
// http://localhost:30001 pass for http://localhost:3000, so every check parses
|
|
3
|
-
// the URL and compares origins.
|
|
4
|
-
|
|
5
|
-
export function originOf(url) {
|
|
6
|
-
try {
|
|
7
|
-
return new URL(String(url)).origin;
|
|
8
|
-
} catch {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function isAppUrl(url, appOrigin) {
|
|
14
|
-
const origin = originOf(url);
|
|
15
|
-
return origin !== null && origin !== 'null' && origin === originOf(appOrigin);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// A wallet request (or log entry) is accepted only from the default execution
|
|
19
|
-
// context of the tab's top frame, on the app origin, while that frame's
|
|
20
|
-
// committed document is an app URL. The committed URL matters because an
|
|
21
|
-
// about:blank document (a popup the app opened) inherits the app origin. For
|
|
22
|
-
// a page target the main frame id equals the target id.
|
|
23
|
-
export function isAppTopFrameContext(context, { targetId, appOrigin, committedUrl }) {
|
|
24
|
-
if (!context || !targetId) return false;
|
|
25
|
-
const aux = context.auxData ?? {};
|
|
26
|
-
return aux.isDefault === true &&
|
|
27
|
-
aux.frameId === targetId &&
|
|
28
|
-
isAppUrl(context.origin, appOrigin) &&
|
|
29
|
-
isAppUrl(committedUrl, appOrigin);
|
|
30
|
-
}
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
// Source of the script the wallet host evaluates in every app document before
|
|
2
|
-
// page scripts. It reports each wallet request the app makes (method, EIP-712
|
|
3
|
-
// primary type, domain/active chain, outcome; no params or signatures) through
|
|
4
|
-
// a CDP binding, and in injected mode also provides the strict test wallet
|
|
5
|
-
// announced over EIP-6963 as io.metamask. It installs itself only in the top
|
|
6
|
-
// frame of a document on the exact app origin: the CDP preload also runs in
|
|
7
|
-
// iframes and after the tab navigates elsewhere. Errors are logged as a code
|
|
8
|
-
// and a fixed category, never as provider text.
|
|
9
|
-
|
|
10
|
-
import { mainnetTypedDataReason } from './mainnet-guard.mjs';
|
|
11
|
-
|
|
12
|
-
export const LOG_BINDING = '__mmTerminalWalletLog';
|
|
13
|
-
export const REQUEST_BINDING = '__mmTerminalWalletRequest';
|
|
14
|
-
export const RESOLVE_FN = '__mmTerminalWalletResolve';
|
|
15
|
-
|
|
16
|
-
export const LOGGED_METHODS = Object.freeze([
|
|
17
|
-
'eth_requestAccounts',
|
|
18
|
-
'wallet_requestPermissions',
|
|
19
|
-
'wallet_revokePermissions',
|
|
20
|
-
'wallet_switchEthereumChain',
|
|
21
|
-
'wallet_addEthereumChain',
|
|
22
|
-
'eth_signTypedData',
|
|
23
|
-
'eth_signTypedData_v3',
|
|
24
|
-
'eth_signTypedData_v4',
|
|
25
|
-
'personal_sign',
|
|
26
|
-
'eth_sign',
|
|
27
|
-
'eth_sendTransaction',
|
|
28
|
-
]);
|
|
29
|
-
|
|
30
|
-
export const ERROR_CATEGORIES = Object.freeze({
|
|
31
|
-
4001: 'user-rejected',
|
|
32
|
-
4100: 'unauthorized',
|
|
33
|
-
4200: 'unsupported-method',
|
|
34
|
-
4900: 'disconnected',
|
|
35
|
-
4901: 'chain-disconnected',
|
|
36
|
-
4902: 'unrecognized-chain',
|
|
37
|
-
[-32602]: 'invalid-params',
|
|
38
|
-
[-32603]: 'internal',
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
function pageMain(config, mainnetTypedDataReason) {
|
|
42
|
-
if (window.top !== window || location.origin !== config.appOrigin) return;
|
|
43
|
-
if (window.__mmTerminalHarness) return;
|
|
44
|
-
// The wallet host's ready check reads this marker on the committed document:
|
|
45
|
-
// the preload ran, and the page's provider is wrapped (covers).
|
|
46
|
-
const wrapped = new WeakSet();
|
|
47
|
-
const harness = {
|
|
48
|
-
signer: config.signer,
|
|
49
|
-
network: config.network,
|
|
50
|
-
wrapped: 0,
|
|
51
|
-
wrapFailures: [],
|
|
52
|
-
covers: (provider) => Boolean(provider) && wrapped.has(provider),
|
|
53
|
-
};
|
|
54
|
-
window.__mmTerminalHarness = harness;
|
|
55
|
-
const logged = new Set(config.loggedMethods);
|
|
56
|
-
// Without the host's binding a wallet request would go unrecorded, so it is
|
|
57
|
-
// refused (fail closed) rather than passed through.
|
|
58
|
-
const unrecorded = () => Object.assign(
|
|
59
|
-
new Error('The harness wallet host is not attached to this document; the request was refused so it cannot go unrecorded.'),
|
|
60
|
-
{ code: 4100 },
|
|
61
|
-
);
|
|
62
|
-
const hasBinding = (binding) => typeof window[binding] === 'function';
|
|
63
|
-
const report = (entry) => {
|
|
64
|
-
try {
|
|
65
|
-
window[config.logBinding](JSON.stringify(entry));
|
|
66
|
-
} catch {
|
|
67
|
-
// Binding unavailable (host detached): the request still proceeds.
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
const describe = (method, params) => {
|
|
71
|
-
const entry = { kind: 'request', method, t: Date.now(), url: location.pathname };
|
|
72
|
-
if (/^eth_signTypedData/.test(method)) {
|
|
73
|
-
try {
|
|
74
|
-
const raw = params?.[1];
|
|
75
|
-
const data = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
76
|
-
entry.primaryType = data?.primaryType ?? null;
|
|
77
|
-
entry.domainName = data?.domain?.name ?? null;
|
|
78
|
-
entry.domainChainId = data?.domain?.chainId == null ? null : Number(BigInt(data.domain.chainId));
|
|
79
|
-
} catch {
|
|
80
|
-
entry.primaryType = null;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (method === 'wallet_switchEthereumChain' || method === 'wallet_addEthereumChain') {
|
|
84
|
-
try {
|
|
85
|
-
entry.toChainId = Number.parseInt(params[0].chainId, 16);
|
|
86
|
-
} catch {
|
|
87
|
-
entry.toChainId = null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return entry;
|
|
91
|
-
};
|
|
92
|
-
const wrap = (provider, source) => {
|
|
93
|
-
if (!provider || typeof provider.request !== 'function' || wrapped.has(provider)) return provider;
|
|
94
|
-
const original = provider.request.bind(provider);
|
|
95
|
-
const request = async (args) => {
|
|
96
|
-
const method = args?.method;
|
|
97
|
-
if (!logged.has(method)) return original(args);
|
|
98
|
-
if (!hasBinding(config.logBinding)) throw unrecorded();
|
|
99
|
-
const entry = { ...describe(method, args?.params), source };
|
|
100
|
-
// Testnet runs never let a mainnet Hyperliquid action reach the signer.
|
|
101
|
-
if (config.network === 'testnet' && /^eth_signTypedData/.test(method)) {
|
|
102
|
-
let reason = null;
|
|
103
|
-
try {
|
|
104
|
-
const raw = args?.params?.[1];
|
|
105
|
-
reason = mainnetTypedDataReason(typeof raw === 'string' ? JSON.parse(raw) : raw);
|
|
106
|
-
} catch {
|
|
107
|
-
reason = null;
|
|
108
|
-
}
|
|
109
|
-
if (reason) {
|
|
110
|
-
report({ ...entry, kind: 'refused-mainnet', reason, outcome: 'refused', errorCode: 4100 });
|
|
111
|
-
throw Object.assign(new Error('Refused: this test run is held to Hyperliquid testnet and the request signs a mainnet action.'), { code: 4100 });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
try {
|
|
115
|
-
entry.activeChainId = Number.parseInt(await original({ method: 'eth_chainId' }), 16);
|
|
116
|
-
} catch {
|
|
117
|
-
entry.activeChainId = null;
|
|
118
|
-
}
|
|
119
|
-
const started = Date.now();
|
|
120
|
-
try {
|
|
121
|
-
const result = await original(args);
|
|
122
|
-
entry.outcome = /sign/i.test(method) ? 'signed' : 'approved';
|
|
123
|
-
entry.durationMs = Date.now() - started;
|
|
124
|
-
report(entry);
|
|
125
|
-
return result;
|
|
126
|
-
} catch (error) {
|
|
127
|
-
const code = Number.isInteger(error?.code) ? error.code : null;
|
|
128
|
-
entry.outcome = code === 4001 ? 'rejected' : 'error';
|
|
129
|
-
entry.errorCode = code;
|
|
130
|
-
entry.errorCategory = config.errorCategories[code] ?? 'other';
|
|
131
|
-
entry.durationMs = Date.now() - started;
|
|
132
|
-
report(entry);
|
|
133
|
-
throw error;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
try {
|
|
137
|
-
provider.request = request;
|
|
138
|
-
} catch {
|
|
139
|
-
// Read-only property: define it instead (below).
|
|
140
|
-
}
|
|
141
|
-
if (provider.request !== request) {
|
|
142
|
-
try {
|
|
143
|
-
Object.defineProperty(provider, 'request', { value: request, configurable: true, writable: true });
|
|
144
|
-
} catch {
|
|
145
|
-
// Frozen provider: recorded below.
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// A provider whose request could not be replaced would sign unrecorded.
|
|
149
|
-
if (provider.request !== request) {
|
|
150
|
-
harness.wrapFailures.push(source);
|
|
151
|
-
return provider;
|
|
152
|
-
}
|
|
153
|
-
wrapped.add(provider);
|
|
154
|
-
harness.wrapped += 1;
|
|
155
|
-
return provider;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
if (config.signer === 'injected') {
|
|
159
|
-
const listeners = {};
|
|
160
|
-
const emit = (event, ...args) => (listeners[event] ?? []).forEach((fn) => {
|
|
161
|
-
try { fn(...args); } catch { /* listener errors stay in the app */ }
|
|
162
|
-
});
|
|
163
|
-
const pending = new Map();
|
|
164
|
-
let nextId = 1;
|
|
165
|
-
window[config.resolveFn] = (id, outcome) => {
|
|
166
|
-
const entry = pending.get(id);
|
|
167
|
-
if (!entry) return;
|
|
168
|
-
pending.delete(id);
|
|
169
|
-
if (outcome.error) entry.reject(Object.assign(new Error(outcome.error.message), { code: outcome.error.code }));
|
|
170
|
-
else entry.resolve(outcome.result);
|
|
171
|
-
};
|
|
172
|
-
let lastChain = null;
|
|
173
|
-
const provider = {
|
|
174
|
-
isMetaMask: true,
|
|
175
|
-
_metamask: { isUnlocked: async () => true },
|
|
176
|
-
request: ({ method, params }) => new Promise((resolve, reject) => {
|
|
177
|
-
if (!hasBinding(config.requestBinding)) {
|
|
178
|
-
reject(unrecorded());
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const id = nextId++;
|
|
182
|
-
pending.set(id, { resolve, reject });
|
|
183
|
-
window[config.requestBinding](JSON.stringify({ id, method, params }));
|
|
184
|
-
}).then((result) => {
|
|
185
|
-
if (method === 'wallet_switchEthereumChain' && params?.[0]?.chainId !== lastChain) {
|
|
186
|
-
lastChain = params[0].chainId;
|
|
187
|
-
emit('chainChanged', lastChain);
|
|
188
|
-
}
|
|
189
|
-
if (method === 'eth_chainId') lastChain = result;
|
|
190
|
-
if (method === 'eth_requestAccounts') emit('connect', { chainId: lastChain ?? '0x1' });
|
|
191
|
-
return result;
|
|
192
|
-
}),
|
|
193
|
-
on: (event, fn) => { (listeners[event] ??= []).push(fn); return provider; },
|
|
194
|
-
removeListener: (event, fn) => { listeners[event] = (listeners[event] ?? []).filter((f) => f !== fn); return provider; },
|
|
195
|
-
enable: () => provider.request({ method: 'eth_requestAccounts' }),
|
|
196
|
-
};
|
|
197
|
-
wrap(provider, 'injected-strict-wallet');
|
|
198
|
-
window.ethereum = provider;
|
|
199
|
-
const info = {
|
|
200
|
-
uuid: '5d1e5b4e-e2e0-4c3f-9a1d-000000000001',
|
|
201
|
-
name: 'MetaMask (strict test wallet)',
|
|
202
|
-
icon: "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'/>",
|
|
203
|
-
rdns: 'io.metamask',
|
|
204
|
-
};
|
|
205
|
-
const announce = () => window.dispatchEvent(new CustomEvent('eip6963:announceProvider', { detail: Object.freeze({ info, provider }) }));
|
|
206
|
-
window.addEventListener('eip6963:requestProvider', announce);
|
|
207
|
-
announce();
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Extension mode: wrap whatever provider MetaMask injects, however the app
|
|
212
|
-
// reaches it (window.ethereum or an EIP-6963 announcement).
|
|
213
|
-
let current = window.ethereum ? wrap(window.ethereum, 'window.ethereum') : undefined;
|
|
214
|
-
try {
|
|
215
|
-
Object.defineProperty(window, 'ethereum', {
|
|
216
|
-
configurable: true,
|
|
217
|
-
get: () => current,
|
|
218
|
-
set: (value) => { current = wrap(value, 'window.ethereum'); },
|
|
219
|
-
});
|
|
220
|
-
} catch {
|
|
221
|
-
// A non-configurable window.ethereum is still wrapped by the poll below.
|
|
222
|
-
}
|
|
223
|
-
window.addEventListener('eip6963:announceProvider', (event) => {
|
|
224
|
-
wrap(event.detail?.provider, `eip6963:${event.detail?.info?.rdns ?? 'unknown'}`);
|
|
225
|
-
}, true);
|
|
226
|
-
let polls = 0;
|
|
227
|
-
const poll = setInterval(() => {
|
|
228
|
-
if (window.ethereum) wrap(window.ethereum, 'window.ethereum');
|
|
229
|
-
if (++polls > 200) clearInterval(poll);
|
|
230
|
-
}, 50);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export function pageScriptSource({ signer, appOrigin, network = 'testnet' }) {
|
|
234
|
-
const origin = new URL(appOrigin).origin;
|
|
235
|
-
const config = {
|
|
236
|
-
signer,
|
|
237
|
-
network,
|
|
238
|
-
appOrigin: origin,
|
|
239
|
-
errorCategories: ERROR_CATEGORIES,
|
|
240
|
-
loggedMethods: LOGGED_METHODS,
|
|
241
|
-
logBinding: LOG_BINDING,
|
|
242
|
-
requestBinding: REQUEST_BINDING,
|
|
243
|
-
resolveFn: RESOLVE_FN,
|
|
244
|
-
};
|
|
245
|
-
return `(${pageMain.toString()})(${JSON.stringify(config)}, ${mainnetTypedDataReason.toString()});`;
|
|
246
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
// EIP-1193 test wallet that enforces MetaMask's typed-data rule: reject
|
|
2
|
-
// eth_signTypedData_v4 whose domain chainId differs from the active chain.
|
|
3
|
-
// Signs with a viem account held by the wallet host; never exposes key
|
|
4
|
-
// material. Ported from the TAT-4032 migration e2e strict wallet.
|
|
5
|
-
|
|
6
|
-
export const DEFAULT_KNOWN_CHAINS = Object.freeze([1, 10, 137, 8453, 42161, 421614, 59144, 59141, 11155111]);
|
|
7
|
-
|
|
8
|
-
const READ_RPC = {
|
|
9
|
-
1: 'https://ethereum-rpc.publicnode.com',
|
|
10
|
-
42161: 'https://arbitrum-one-rpc.publicnode.com',
|
|
11
|
-
421614: 'https://arbitrum-sepolia-rpc.publicnode.com',
|
|
12
|
-
59144: 'https://linea-rpc.publicnode.com',
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// Only these reads go to the public RPC. Anything else the wallet does not
|
|
16
|
-
// answer itself (eth_sendRawTransaction, account or filter methods, unknown
|
|
17
|
-
// wallet_* calls) is refused before any network request.
|
|
18
|
-
export const READ_ONLY_RPC_METHODS = Object.freeze([
|
|
19
|
-
'eth_blockNumber',
|
|
20
|
-
'eth_call',
|
|
21
|
-
'eth_estimateGas',
|
|
22
|
-
'eth_feeHistory',
|
|
23
|
-
'eth_gasPrice',
|
|
24
|
-
'eth_getBalance',
|
|
25
|
-
'eth_getBlockByHash',
|
|
26
|
-
'eth_getBlockByNumber',
|
|
27
|
-
'eth_getCode',
|
|
28
|
-
'eth_getLogs',
|
|
29
|
-
'eth_getStorageAt',
|
|
30
|
-
'eth_getTransactionByHash',
|
|
31
|
-
'eth_getTransactionCount',
|
|
32
|
-
'eth_getTransactionReceipt',
|
|
33
|
-
'eth_maxPriorityFeePerGas',
|
|
34
|
-
'web3_clientVersion',
|
|
35
|
-
]);
|
|
36
|
-
const READ_ONLY = new Set(READ_ONLY_RPC_METHODS);
|
|
37
|
-
|
|
38
|
-
function rpcError(message, code) {
|
|
39
|
-
return Object.assign(new Error(message), { code });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function toBigIntDeep(types, primaryType, message) {
|
|
43
|
-
const out = {};
|
|
44
|
-
for (const field of types[primaryType] ?? []) {
|
|
45
|
-
const value = message[field.name];
|
|
46
|
-
if (value === undefined) continue;
|
|
47
|
-
if (/^u?int\d*$/u.test(field.type)) out[field.name] = BigInt(value);
|
|
48
|
-
else if (types[field.type]) out[field.name] = toBigIntDeep(types, field.type, value);
|
|
49
|
-
else out[field.name] = value;
|
|
50
|
-
}
|
|
51
|
-
return out;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function createStrictWallet({
|
|
55
|
-
account,
|
|
56
|
-
chainId = 42161,
|
|
57
|
-
knownChains = DEFAULT_KNOWN_CHAINS,
|
|
58
|
-
refuseSwitch = false,
|
|
59
|
-
fetchImpl = globalThis.fetch,
|
|
60
|
-
}) {
|
|
61
|
-
let activeChain = chainId;
|
|
62
|
-
const known = new Set(knownChains);
|
|
63
|
-
let rpcId = 1;
|
|
64
|
-
|
|
65
|
-
async function request({ method, params = [] }) {
|
|
66
|
-
switch (method) {
|
|
67
|
-
case 'eth_chainId':
|
|
68
|
-
return `0x${activeChain.toString(16)}`;
|
|
69
|
-
case 'net_version':
|
|
70
|
-
return String(activeChain);
|
|
71
|
-
case 'eth_accounts':
|
|
72
|
-
case 'eth_requestAccounts':
|
|
73
|
-
return [account.address];
|
|
74
|
-
case 'wallet_requestPermissions':
|
|
75
|
-
case 'wallet_getPermissions':
|
|
76
|
-
return [{ parentCapability: 'eth_accounts', caveats: [{ type: 'restrictReturnedAccounts', value: [account.address.toLowerCase()] }] }];
|
|
77
|
-
case 'wallet_revokePermissions':
|
|
78
|
-
return null;
|
|
79
|
-
case 'metamask_getProviderState':
|
|
80
|
-
return { accounts: [account.address.toLowerCase()], chainId: `0x${activeChain.toString(16)}`, isUnlocked: true, networkVersion: String(activeChain) };
|
|
81
|
-
case 'wallet_switchEthereumChain': {
|
|
82
|
-
const id = Number.parseInt(params[0].chainId, 16);
|
|
83
|
-
if (refuseSwitch) throw rpcError('User rejected the request.', 4001);
|
|
84
|
-
if (!known.has(id)) throw rpcError(`Unrecognized chain ID ${params[0].chainId}`, 4902);
|
|
85
|
-
activeChain = id;
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
case 'wallet_addEthereumChain':
|
|
89
|
-
known.add(Number.parseInt(params[0].chainId, 16));
|
|
90
|
-
return null;
|
|
91
|
-
case 'eth_signTypedData_v4': {
|
|
92
|
-
const [from, raw] = params;
|
|
93
|
-
const data = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
94
|
-
const domainChain = Number(BigInt(data.domain.chainId));
|
|
95
|
-
if (String(from).toLowerCase() !== account.address.toLowerCase()) throw rpcError('Unknown account', 4100);
|
|
96
|
-
if (domainChain !== activeChain) {
|
|
97
|
-
throw rpcError(`Provided chainId "${domainChain}" must match the active chainId "${activeChain}"`, -32602);
|
|
98
|
-
}
|
|
99
|
-
const types = { ...data.types };
|
|
100
|
-
delete types.EIP712Domain;
|
|
101
|
-
return account.signTypedData({
|
|
102
|
-
domain: { ...data.domain, chainId: domainChain },
|
|
103
|
-
types,
|
|
104
|
-
primaryType: data.primaryType,
|
|
105
|
-
message: toBigIntDeep(types, data.primaryType, data.message),
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
case 'personal_sign': {
|
|
109
|
-
const [message, from] = params;
|
|
110
|
-
if (String(from).toLowerCase() !== account.address.toLowerCase()) throw rpcError('Unknown account', 4100);
|
|
111
|
-
return account.signMessage({ message: { raw: message } });
|
|
112
|
-
}
|
|
113
|
-
case 'eth_sendTransaction':
|
|
114
|
-
case 'eth_sign':
|
|
115
|
-
throw rpcError(`${method} is not supported by the strict test wallet`, 4200);
|
|
116
|
-
default: {
|
|
117
|
-
if (!READ_ONLY.has(method)) throw rpcError(`${method} is not supported by the strict test wallet`, 4200);
|
|
118
|
-
const url = READ_RPC[activeChain];
|
|
119
|
-
if (!url) throw rpcError(`No read RPC for chain ${activeChain}`, 4200);
|
|
120
|
-
const response = await fetchImpl(url, {
|
|
121
|
-
method: 'POST',
|
|
122
|
-
headers: { 'content-type': 'application/json' },
|
|
123
|
-
body: JSON.stringify({ jsonrpc: '2.0', id: rpcId++, method, params }),
|
|
124
|
-
});
|
|
125
|
-
const body = await response.json();
|
|
126
|
-
if (body.error) throw rpcError(body.error.message, body.error.code);
|
|
127
|
-
return body.result;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
request,
|
|
134
|
-
get chainId() {
|
|
135
|
-
return activeChain;
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
}
|