@recoillink/cli 0.0.0-stage → 45.0.1

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 (81) hide show
  1. package/LICENSE.md +193 -0
  2. package/README.md +149 -2
  3. package/bundle/154.index.js +462 -0
  4. package/bundle/230.index.js +569 -0
  5. package/bundle/25.index.js +9569 -0
  6. package/bundle/267.index.js +1386 -0
  7. package/bundle/308.index.js +5121 -0
  8. package/bundle/367.index.js +4 -0
  9. package/bundle/369.index.js +3443 -0
  10. package/bundle/529.index.js +3596 -0
  11. package/bundle/576.index.js +36 -0
  12. package/bundle/610.index.js +86 -0
  13. package/bundle/617.index.js +1612 -0
  14. package/bundle/628.index.js +152 -0
  15. package/bundle/633.index.js +86 -0
  16. package/bundle/697.index.js +410 -0
  17. package/bundle/7183ea1c1bf0a5da980d.js +214 -0
  18. package/bundle/748.index.js +672 -0
  19. package/bundle/78.index.js +372 -0
  20. package/bundle/841.index.js +2093 -0
  21. package/bundle/868.index.js +290 -0
  22. package/bundle/902.index.js +173 -0
  23. package/bundle/956.index.js +9901 -0
  24. package/bundle/aleo_wasm.wasm +0 -0
  25. package/bundle/aleo_wasm1.wasm +0 -0
  26. package/bundle/build/Release/bigint_buffer.node +0 -0
  27. package/bundle/file.js +12 -0
  28. package/bundle/index.js +4 -0
  29. package/bundle/package.json +3 -0
  30. package/bundle/worker-pipeline.js +38 -0
  31. package/bundle/worker.js +54 -0
  32. package/bundle/worker1.js +171 -0
  33. package/bundle/worker2.js +19834 -0
  34. package/bundle/worker3.js +19834 -0
  35. package/examples/aleo/core-config.yaml +19 -0
  36. package/examples/ccip/ccip-warp-route.yaml +26 -0
  37. package/examples/ccip/multi-chain-ccip-warp-route.yaml +81 -0
  38. package/examples/chain-config.yaml +42 -0
  39. package/examples/contract-artifacts.yaml +20 -0
  40. package/examples/core-config.yaml +19 -0
  41. package/examples/cosmosnative/core-config.yaml +20 -0
  42. package/examples/cosmosnative/warp-route-deployment.yaml +21 -0
  43. package/examples/crosschain/README.md +31 -0
  44. package/examples/crosschain/cosmosnative/core-config.yaml +69 -0
  45. package/examples/crosschain/ethereum/core-config.yaml +70 -0
  46. package/examples/crosschain/radix/core-config.yaml +96 -0
  47. package/examples/fork/file-transactions.yaml +5 -0
  48. package/examples/fork/timelock-testing.yaml +36 -0
  49. package/examples/fork/warp-route-update.yaml +100 -0
  50. package/examples/hooks.yaml +70 -0
  51. package/examples/ism-advanced.yaml +33 -0
  52. package/examples/ism.yaml +13 -0
  53. package/examples/radix/core-config.yaml +29 -0
  54. package/examples/sealevel/core-config-apply.yaml +7 -0
  55. package/examples/sealevel/core-config-composite-ism.yaml +21 -0
  56. package/examples/sealevel/core-config.yaml +12 -0
  57. package/examples/sealevel/igp-hook-config.yaml +13 -0
  58. package/examples/sealevel/warp-config-routing-message-id-multisig-ism.yaml +21 -0
  59. package/examples/starknet/core-config.yaml +20 -0
  60. package/examples/submit/strategy/file-strategy.yaml +8 -0
  61. package/examples/submit/strategy/gnosis-chain-strategy.yaml +10 -0
  62. package/examples/submit/strategy/gnosis-chain-tx-builder-strategy.yaml +6 -0
  63. package/examples/submit/strategy/gnosis-strategy-avalanche.yaml +4 -0
  64. package/examples/submit/strategy/gnosis-tx-builder-ica-strategy.yaml +20 -0
  65. package/examples/submit/strategy/ica-timelock-strategy.yaml +15 -0
  66. package/examples/submit/strategy/impersonated-account-strategy.yaml +4 -0
  67. package/examples/submit/strategy/json-rpc-chain-strategy.yaml +8 -0
  68. package/examples/submit/strategy/json-rpc-ica-strategy.yaml +13 -0
  69. package/examples/submit/strategy/json-rpc-strategy.yaml +3 -0
  70. package/examples/submit/strategy/json-rpc-timelock-strategy.yaml +17 -0
  71. package/examples/submit/strategy/starknet-json-rpc-chain-strategy.yaml +11 -0
  72. package/examples/submit/transactions/anvil-transactions.yaml +10 -0
  73. package/examples/submit/transactions/avalanche-transactions.json +8 -0
  74. package/examples/submit/transactions/sepolia-transactions.json +8 -0
  75. package/examples/tron-core-config.yaml +18 -0
  76. package/examples/warp-base.yaml +24 -0
  77. package/examples/warp-config-predicate-mainnet.yaml +14 -0
  78. package/examples/warp-deployed-predicate-mainnet.yaml +19 -0
  79. package/examples/warp-ethereum.yaml +19 -0
  80. package/examples/warp-route-deployment.yaml +21 -0
  81. package/package.json +117 -3
@@ -0,0 +1,672 @@
1
+ export const id = 748;
2
+ export const ids = [748];
3
+ export const modules = {
4
+
5
+ /***/ 60367:
6
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
7
+
8
+
9
+ // EXPORTS
10
+ __webpack_require__.d(__webpack_exports__, {
11
+ createSvmForkManager: () => (/* reexport */ createSvmForkManager),
12
+ parseSvmForkConfig: () => (/* reexport */ parseSvmForkConfig)
13
+ });
14
+
15
+ // UNUSED EXPORTS: PrintableSvmTransactionSchema, SURFPOOL_MIN_VERSION, SolanaCluster, SurfpoolDatasourceMode, SvmForkManager, SvmRawForkConfigSchema, runSurfpoolNode
16
+
17
+ // EXTERNAL MODULE: external "child_process"
18
+ var external_child_process_ = __webpack_require__(35317);
19
+ // EXTERNAL MODULE: external "node:fs"
20
+ var external_node_fs_ = __webpack_require__(73024);
21
+ // EXTERNAL MODULE: external "node:net"
22
+ var external_node_net_ = __webpack_require__(77030);
23
+ // EXTERNAL MODULE: external "node:os"
24
+ var external_node_os_ = __webpack_require__(48161);
25
+ // EXTERNAL MODULE: external "node:path"
26
+ var external_node_path_ = __webpack_require__(76760);
27
+ // EXTERNAL MODULE: ../forking-sdk/dist/index.js + 3 modules
28
+ var dist = __webpack_require__(65310);
29
+ // EXTERNAL MODULE: ../utils/dist/logging.js
30
+ var logging = __webpack_require__(94523);
31
+ // EXTERNAL MODULE: ../utils/dist/typeof.js
32
+ var dist_typeof = __webpack_require__(73689);
33
+ // EXTERNAL MODULE: ../utils/dist/validation.js
34
+ var validation = __webpack_require__(21387);
35
+ // EXTERNAL MODULE: ../svm-sdk/dist/rpc.js + 9 modules
36
+ var dist_rpc = __webpack_require__(48080);
37
+ ;// CONCATENATED MODULE: ../svm-sdk/dist/fork/surfpool-node.js
38
+ // eslint-disable-next-line import/no-nodejs-modules
39
+
40
+ // eslint-disable-next-line import/no-nodejs-modules
41
+
42
+ // eslint-disable-next-line import/no-nodejs-modules
43
+
44
+ // eslint-disable-next-line import/no-nodejs-modules
45
+
46
+ // eslint-disable-next-line import/no-nodejs-modules
47
+
48
+
49
+
50
+
51
+ const logger = logging/* rootLogger */.Jk.child({ module: 'surfpool-node' });
52
+ // Minimum acceptable local `surfpool` version; aligned with the docker image
53
+ // `surfpool/surfpool:1.5.0` used by the container runner in test infra.
54
+ const SURFPOOL_MIN_VERSION = '1.5.0';
55
+ // Install guidance surfaced whenever a compatible `surfpool` binary is missing.
56
+ // Points at the pinned, checksum-verified release rather than the mutable
57
+ // `run.surfpool.run` installer, so an operator (or agent) never pipes remote
58
+ // code to a shell.
59
+ const SURFPOOL_INSTALL_GUIDANCE = `Install a pinned surfpool ${SURFPOOL_MIN_VERSION}+ release from ` +
60
+ 'https://github.com/txtx/surfpool/releases and verify its SHA-256 checksum; ' +
61
+ 'do not pipe the mutable run.surfpool.run installer to a shell.';
62
+ // Env var surfpool reads for its fork datasource. Passing the (possibly
63
+ // credential-bearing) upstream URL this way keeps it out of the process argv.
64
+ const SURFPOOL_DATASOURCE_RPC_URL_ENV = 'SURFPOOL_DATASOURCE_RPC_URL';
65
+ // Per-probe RPC timeout so a single hung request fails fast and the bounded
66
+ // readiness loop can continue.
67
+ const RPC_PROBE_TIMEOUT_MS = 5000;
68
+ // Cap on the retained tail of surfpool stderr, surfaced in exit errors.
69
+ const STDERR_TAIL_MAX = 8192;
70
+ const REDACTED_DATASOURCE_URL = '<redacted-datasource-url>';
71
+ // URL userinfo credentials (scheme://user:pass@host). A defense-in-depth
72
+ // backstop that scrubs a reformatted/percent-encoded credential the exact
73
+ // datasource-URL match would miss.
74
+ const URL_USERINFO_CREDENTIALS_RE = /\/\/[^/@\s]+:[^/@\s]+@/g;
75
+ /**
76
+ * Scrubs secrets from surfpool stderr before it is embedded in a surfaced error.
77
+ * surfpool prints stderr verbatim (not shell-escaped), so the known
78
+ * credential-bearing datasource URL is removed by exact-string replacement;
79
+ * stripping URL userinfo credentials is a backstop for any other credential URL.
80
+ */
81
+ function redactSurfpoolStderr(detail, datasourceUrl) {
82
+ const withoutDatasource = (0,dist_typeof/* isNullish */.u)(datasourceUrl)
83
+ ? detail
84
+ : detail.split(datasourceUrl).join(REDACTED_DATASOURCE_URL);
85
+ return withoutDatasource.replace(URL_USERINFO_CREDENTIALS_RE, '//<redacted>@');
86
+ }
87
+ const SurfpoolDatasourceMode = {
88
+ Fork: 'fork',
89
+ Network: 'network',
90
+ Offline: 'offline',
91
+ };
92
+ const SolanaCluster = {
93
+ Mainnet: 'mainnet',
94
+ Devnet: 'devnet',
95
+ Testnet: 'testnet',
96
+ };
97
+ const SURFPOOL_BINARY_PATHS = [
98
+ (0,external_node_path_.join)((0,external_node_os_.homedir)(), '.cargo/bin'),
99
+ '/opt/homebrew/bin',
100
+ '/usr/local/bin',
101
+ ];
102
+ function parseVersion(version) {
103
+ const match = version.match(/(\d+)\.(\d+)\.(\d+)/);
104
+ if (!match)
105
+ return null;
106
+ const [, major, minor, patch] = match;
107
+ (0,validation/* assert */.v)(major && minor && patch, `Invalid surfpool version: ${version}`);
108
+ return {
109
+ major: parseInt(major, 10),
110
+ minor: parseInt(minor, 10),
111
+ patch: parseInt(patch, 10),
112
+ };
113
+ }
114
+ function meetsMinVersion(version, min) {
115
+ if (version.major !== min.major)
116
+ return version.major > min.major;
117
+ if (version.minor !== min.minor)
118
+ return version.minor > min.minor;
119
+ return version.patch >= min.patch;
120
+ }
121
+ function getSurfpoolVersion(binaryPath) {
122
+ try {
123
+ const output = (0,external_child_process_.execFileSync)(binaryPath, ['--version'], {
124
+ encoding: 'utf-8',
125
+ });
126
+ const match = output.match(/surfpool\s+(\d+\.\d+\.\d+)/);
127
+ return match?.[1] ?? null;
128
+ }
129
+ catch (error) {
130
+ logger.debug({ err: error }, `failed to get surfpool version at ${binaryPath}`);
131
+ return null;
132
+ }
133
+ }
134
+ function findSurfpoolCandidates() {
135
+ const candidates = [];
136
+ for (const basePath of SURFPOOL_BINARY_PATHS) {
137
+ const binaryPath = (0,external_node_path_.join)(basePath, 'surfpool');
138
+ if ((0,external_node_fs_.existsSync)(binaryPath)) {
139
+ const version = getSurfpoolVersion(binaryPath);
140
+ if (version) {
141
+ candidates.push({ path: binaryPath, version });
142
+ }
143
+ }
144
+ }
145
+ try {
146
+ const result = (0,external_child_process_.execSync)('which surfpool', { encoding: 'utf-8' }).trim();
147
+ if (result && (0,external_node_fs_.existsSync)(result)) {
148
+ const version = getSurfpoolVersion(result);
149
+ if (version && !candidates.some((c) => c.path === result)) {
150
+ candidates.push({ path: result, version });
151
+ }
152
+ }
153
+ }
154
+ catch (error) {
155
+ logger.debug({ err: error }, 'surfpool not found in PATH');
156
+ }
157
+ return candidates;
158
+ }
159
+ function buildSurfpoolArgs(config, datasource, bindHost) {
160
+ const args = [
161
+ 'start',
162
+ '--no-tui',
163
+ '--no-studio',
164
+ '--no-deploy',
165
+ '--host',
166
+ bindHost,
167
+ '--port',
168
+ String(config.rpcPort),
169
+ ];
170
+ if (!(0,dist_typeof/* isNullish */.u)(config.wsPort)) {
171
+ args.push('--ws-port', String(config.wsPort));
172
+ }
173
+ if (datasource.mode === SurfpoolDatasourceMode.Network) {
174
+ args.push('--network', datasource.network);
175
+ }
176
+ else if (datasource.mode === SurfpoolDatasourceMode.Offline) {
177
+ args.push('--offline');
178
+ }
179
+ // Fork mode: the datasource URL is passed via the SURFPOOL_DATASOURCE_RPC_URL
180
+ // env (see buildSurfpoolDatasourceEnv) rather than argv.
181
+ if (config.skipSignatureVerification) {
182
+ args.push('--skip-signature-verification');
183
+ }
184
+ if (config.skipBlockhashCheck) {
185
+ args.push('--skip-blockhash-check');
186
+ }
187
+ if (config.airdrops && config.airdrops.addresses.length > 0) {
188
+ for (const address of config.airdrops.addresses) {
189
+ args.push('--airdrop', address);
190
+ }
191
+ args.push('--airdrop-amount', config.airdrops.lamports.toString());
192
+ }
193
+ return args;
194
+ }
195
+ /**
196
+ * Spawn env carrying surfpool's fork datasource URL. Empty for network/offline
197
+ * datasources, which take no credentials and are expressed via argv flags.
198
+ */
199
+ function buildSurfpoolDatasourceEnv(datasource) {
200
+ if (datasource.mode !== SurfpoolDatasourceMode.Fork) {
201
+ return {};
202
+ }
203
+ return { [SURFPOOL_DATASOURCE_RPC_URL_ENV]: datasource.rpcUrl };
204
+ }
205
+ /**
206
+ * Per-attempt abort signal that fires after `timeoutMs`, or immediately when
207
+ * `parent` aborts (so a caller cancelling the readiness loop also cancels the
208
+ * in-flight probe request). Composed manually to stay usable on Node <17, which
209
+ * lacks `AbortSignal.timeout`/`AbortSignal.any`. `dispose` clears the timer and
210
+ * detaches the parent listener so nothing lingers between attempts.
211
+ */
212
+ function probeTimeoutSignal(timeoutMs, parent) {
213
+ const controller = new AbortController();
214
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
215
+ const onParentAbort = () => controller.abort();
216
+ if (parent) {
217
+ if (parent.aborted) {
218
+ controller.abort();
219
+ }
220
+ else {
221
+ parent.addEventListener('abort', onParentAbort, { once: true });
222
+ }
223
+ }
224
+ const dispose = () => {
225
+ clearTimeout(timer);
226
+ parent?.removeEventListener('abort', onParentAbort);
227
+ };
228
+ return { signal: controller.signal, dispose };
229
+ }
230
+ async function waitForSolanaRpcReady(rpcUrl, signal) {
231
+ const rpc = (0,dist_rpc/* createRpc */.C8)(rpcUrl);
232
+ await (0,dist/* waitUntilReady */.bs)(async () => {
233
+ const { signal: probeSignal, dispose } = probeTimeoutSignal(RPC_PROBE_TIMEOUT_MS, signal);
234
+ try {
235
+ const health = await rpc.getHealth().send({ abortSignal: probeSignal });
236
+ (0,validation/* assert */.v)(health === 'ok', `surfpool RPC not healthy: ${health}`);
237
+ }
238
+ finally {
239
+ dispose();
240
+ }
241
+ }, { attempts: 60, baseRetryMs: 1000, signal });
242
+ }
243
+ /**
244
+ * Rejects if `port` on 127.0.0.1 is already bound. A bind-test up front closes
245
+ * the port-collision race: proving RPC health after spawn can otherwise pass
246
+ * against an unrelated node already listening on the port, before our freshly
247
+ * spawned child fails with EADDRINUSE.
248
+ */
249
+ async function assertPortAvailable(port) {
250
+ await new Promise((resolve, reject) => {
251
+ const server = (0,external_node_net_.createServer)();
252
+ server.once('error', (error) => {
253
+ const code = 'code' in error ? error.code : undefined;
254
+ reject(code === 'EADDRINUSE'
255
+ ? new Error(`port ${port} is already in use`)
256
+ : error);
257
+ });
258
+ server.once('listening', () => {
259
+ server.close(() => resolve());
260
+ });
261
+ server.listen(port, '127.0.0.1');
262
+ });
263
+ }
264
+ // A single process-level `exit` hook kills every still-running fork, rather than
265
+ // one listener per fork — which would trip MaxListenersExceededWarning past ten
266
+ // forks and retain each child's closure until process exit. A fork joins the
267
+ // registry on start and leaves when it is killed or its child exits.
268
+ const runningForkKills = new Set();
269
+ let forkExitHookInstalled = false;
270
+ function trackForkExit(killFork) {
271
+ runningForkKills.add(killFork);
272
+ if (!forkExitHookInstalled) {
273
+ forkExitHookInstalled = true;
274
+ process.once('exit', () => {
275
+ for (const kill of Array.from(runningForkKills)) {
276
+ kill();
277
+ }
278
+ });
279
+ }
280
+ return () => {
281
+ runningForkKills.delete(killFork);
282
+ };
283
+ }
284
+ async function startLocalSurfpool(config, binaryPath, waitForRpcReady = waitForSolanaRpcReady) {
285
+ // Fail fast if any bind port is taken, before spawning, so we never treat
286
+ // another process's RPC as our fork and never spawn a doomed child that would
287
+ // fail to bind an occupied ws port.
288
+ await assertPortAvailable(config.rpcPort);
289
+ if (!(0,dist_typeof/* isNullish */.u)(config.wsPort)) {
290
+ await assertPortAvailable(config.wsPort);
291
+ }
292
+ const args = buildSurfpoolArgs(config, config.datasource, '127.0.0.1');
293
+ // Suppress surfpool's own logs (its default ./.surfpool/logs dir would clutter
294
+ // the working dir); startup/bind failures still surface on stderr, drained below.
295
+ args.push('--log-level', 'none');
296
+ const proc = (0,external_child_process_.spawn)(binaryPath, args, {
297
+ stdio: ['ignore', 'ignore', 'pipe'],
298
+ detached: false,
299
+ env: { ...process.env, ...buildSurfpoolDatasourceEnv(config.datasource) },
300
+ });
301
+ // Drain stderr into a bounded tail; reading it also keeps the pipe from
302
+ // filling and blocking the child.
303
+ let stderrTail = '';
304
+ proc.stderr?.on('data', (chunk) => {
305
+ stderrTail = (stderrTail + chunk.toString()).slice(-STDERR_TAIL_MAX);
306
+ });
307
+ const rpcUrl = `http://127.0.0.1:${config.rpcPort}`;
308
+ const datasourceUrl = config.datasource.mode === SurfpoolDatasourceMode.Fork
309
+ ? config.datasource.rpcUrl
310
+ : undefined;
311
+ const kill = () => {
312
+ // Leave the process-exit registry whenever the child is gone (killed here,
313
+ // or exited/errored below) so a dead fork never keeps being tracked.
314
+ untrackFork();
315
+ if (config.keepRunning) {
316
+ return;
317
+ }
318
+ if ((0,dist_typeof/* isNullish */.u)(proc.exitCode)) {
319
+ proc.kill('SIGTERM');
320
+ }
321
+ };
322
+ const untrackFork = trackForkExit(kill);
323
+ // A failed spawn (e.g. ENOENT) emits `error` with no guaranteed `exit`, so the
324
+ // readiness race must reject on it — otherwise readiness burns the full probe
325
+ // timeout and reports a misleading RPC error instead of the real spawn failure.
326
+ // Attach synchronously here so no `error` can fire before a listener exists.
327
+ const errored = new Promise((_, reject) => {
328
+ proc.once('error', (error) => {
329
+ untrackFork();
330
+ logger.debug({ err: error }, 'surfpool process error');
331
+ reject(error);
332
+ });
333
+ });
334
+ // A spawn error arriving after readiness (or exit) has already settled the race
335
+ // must not surface as an unhandled rejection.
336
+ errored.catch(() => { });
337
+ // Capture the child's exit synchronously after spawn rather than lazily inside
338
+ // `waitForReady`: `exit` is not replayed, so a caller that waits after the
339
+ // child has already exited must still observe it instead of polling to the
340
+ // readiness bound. Rejecting here also drops the fork from the exit registry.
341
+ const exited = new Promise((_, reject) => {
342
+ proc.once('exit', (code, signal) => {
343
+ untrackFork();
344
+ const detail = redactSurfpoolStderr(stderrTail.trim(), datasourceUrl);
345
+ reject(new Error(`surfpool exited before its RPC was ready (code=${code}, signal=${signal})` +
346
+ (detail ? `: ${detail}` : '')));
347
+ });
348
+ });
349
+ // A later exit (e.g. on kill once readiness has won) must not surface as an
350
+ // unhandled rejection after the race settles.
351
+ exited.catch(() => { });
352
+ const waitForReady = async () => {
353
+ // Abort the readiness probe the instant the race settles so no retry timer
354
+ // keeps polling a dead port after an early exit or spawn error wins.
355
+ const controller = new AbortController();
356
+ try {
357
+ await Promise.race([
358
+ waitForRpcReady(rpcUrl, controller.signal),
359
+ exited,
360
+ errored,
361
+ ]);
362
+ }
363
+ finally {
364
+ controller.abort();
365
+ }
366
+ };
367
+ return { node: { rpcUrl, kill }, waitForReady };
368
+ }
369
+ // A caller-supplied binary is an explicit choice, so failures name the specific
370
+ // cause (missing / not executable / too old) instead of the generic auto-
371
+ // discovery "no compatible binary" message, which would otherwise report the
372
+ // substituted "unknown" version and hide the real problem.
373
+ function resolveExplicitBinary(binaryPath, min) {
374
+ (0,validation/* assert */.v)((0,external_node_fs_.existsSync)(binaryPath), `surfpool binary not found at ${binaryPath}`);
375
+ const version = getSurfpoolVersion(binaryPath);
376
+ (0,validation/* assert */.v)(version, `surfpool binary at ${binaryPath} could not be run (check it is executable and 'surfpool --version' works).`);
377
+ const parsed = parseVersion(version);
378
+ (0,validation/* assert */.v)(parsed && meetsMinVersion(parsed, min), `surfpool at ${binaryPath} is version ${version} but ${SURFPOOL_MIN_VERSION}+ is required. ` +
379
+ SURFPOOL_INSTALL_GUIDANCE);
380
+ return { path: binaryPath, version };
381
+ }
382
+ function resolveDiscoveredBinary(min) {
383
+ const candidates = findSurfpoolCandidates();
384
+ const match = candidates.find((candidate) => {
385
+ const parsed = parseVersion(candidate.version);
386
+ return parsed !== null && meetsMinVersion(parsed, min);
387
+ });
388
+ (0,validation/* assert */.v)(match, candidates.length === 0
389
+ ? `surfpool ${SURFPOOL_MIN_VERSION}+ is required but no surfpool binary was found on PATH. ` +
390
+ SURFPOOL_INSTALL_GUIDANCE
391
+ : `surfpool ${SURFPOOL_MIN_VERSION}+ is required but only found version(s) ` +
392
+ `${candidates.map((c) => c.version).join(', ')}. ` +
393
+ SURFPOOL_INSTALL_GUIDANCE);
394
+ return match;
395
+ }
396
+ /**
397
+ * Starts a surfpool node from a locally-installed `surfpool` binary (version
398
+ * {@link SURFPOOL_MIN_VERSION} or newer) and waits for its RPC to be ready.
399
+ * An explicit `config.binaryPath` is validated up front with a specific error;
400
+ * otherwise the PATH is searched and an install-guidance error is thrown if no
401
+ * compatible binary is found.
402
+ */
403
+ async function runSurfpoolNode(config) {
404
+ const min = parseVersion(SURFPOOL_MIN_VERSION);
405
+ (0,validation/* assert */.v)(min, `Invalid SURFPOOL_MIN_VERSION: ${SURFPOOL_MIN_VERSION}`);
406
+ const match = config.binaryPath
407
+ ? resolveExplicitBinary(config.binaryPath, min)
408
+ : resolveDiscoveredBinary(min);
409
+ logger.debug(`Using local surfpool binary: ${match.path} (v${match.version})`);
410
+ const { node, waitForReady } = await startLocalSurfpool(config, match.path);
411
+ try {
412
+ await waitForReady();
413
+ }
414
+ catch (error) {
415
+ node.kill();
416
+ throw error;
417
+ }
418
+ return node;
419
+ }
420
+ //# sourceMappingURL=surfpool-node.js.map
421
+ // EXTERNAL MODULE: ../../node_modules/.pnpm/@solana+codecs-strings@8.2.0_@typescript+typescript6@6.0.2_fastestsmallesttextencoderdecoder@1.0.22/node_modules/@solana/codecs-strings/dist/index.node.mjs
422
+ var index_node = __webpack_require__(48990);
423
+ // EXTERNAL MODULE: ../../node_modules/.pnpm/@solana+transactions@8.2.0_@typescript+typescript6@6.0.2_fastestsmallesttextencoderdecoder@1.0.22/node_modules/@solana/transactions/dist/index.node.mjs
424
+ var dist_index_node = __webpack_require__(11508);
425
+ // EXTERNAL MODULE: ../../node_modules/.pnpm/@solana+transaction-messages@8.2.0_@typescript+typescript6@6.0.2_fastestsmallesttextencoderdecoder@1.0.22/node_modules/@solana/transaction-messages/dist/index.node.mjs
426
+ var transaction_messages_dist_index_node = __webpack_require__(13464);
427
+ // EXTERNAL MODULE: ../utils/dist/async.js
428
+ var dist_async = __webpack_require__(14918);
429
+ // EXTERNAL MODULE: ../svm-sdk/dist/accounts/address-lookup-table.js
430
+ var address_lookup_table = __webpack_require__(96971);
431
+ // EXTERNAL MODULE: ../svm-sdk/dist/constants.js
432
+ var constants = __webpack_require__(94327);
433
+ // EXTERNAL MODULE: ../svm-sdk/dist/tx.js
434
+ var tx = __webpack_require__(55960);
435
+ // EXTERNAL MODULE: ../svm-sdk/dist/fork/impersonation.js
436
+ var impersonation = __webpack_require__(44391);
437
+ ;// CONCATENATED MODULE: ../svm-sdk/dist/fork/svm-fork-manager.js
438
+
439
+
440
+
441
+
442
+
443
+
444
+
445
+
446
+ const svm_fork_manager_logger = logging/* rootLogger */.Jk.child({ module: 'svm-fork-manager' });
447
+ const RPC_COMMITMENT = 'confirmed';
448
+ const POLL_INTERVAL_MS = 500;
449
+ const POLL_MAX_ATTEMPTS = 60;
450
+ const RESOLVE_ALT_CONCURRENCY = 4;
451
+ const base58Encoder = (0,index_node/* getBase58Encoder */.nZ)();
452
+ const transactionDecoder = (0,dist_index_node/* getTransactionDecoder */.BX)();
453
+ const compiledMessageDecoder = (0,transaction_messages_dist_index_node/* getCompiledTransactionMessageDecoder */.fr)();
454
+ /**
455
+ * Fetches the addresses stored in each address-lookup table referenced by a
456
+ * compiled message, producing the map kit needs to decompile the message and
457
+ * re-compress it against the same tables. Returns `undefined` for a message
458
+ * that uses no lookup tables (so callers can skip compression entirely).
459
+ */
460
+ async function resolveForkLookupTables(rpc, compiledMessage) {
461
+ const lookups = 'addressTableLookups' in compiledMessage
462
+ ? compiledMessage.addressTableLookups
463
+ : undefined;
464
+ if ((0,dist_typeof/* isNullish */.u)(lookups) || lookups.length === 0) {
465
+ return undefined;
466
+ }
467
+ const entries = await (0,dist_async/* concurrentMap */.q1)(RESOLVE_ALT_CONCURRENCY, lookups, async (lookup) => {
468
+ const state = await (0,address_lookup_table/* fetchAddressLookupTableState */.a)(rpc, lookup.lookupTableAddress);
469
+ return [lookup.lookupTableAddress, state.addresses];
470
+ });
471
+ return Object.fromEntries(entries);
472
+ }
473
+ /**
474
+ * Rebuilds the wire transaction to replay against a fork.
475
+ *
476
+ * `transaction_base58` is serialized without the compute-budget instruction
477
+ * (an external executor — Squads / file submitter — prepends it from
478
+ * `computeUnits`, defaulting to {@link DEFAULT_COMPUTE_UNITS}). Replaying it
479
+ * verbatim leaves the tx under the runtime per-instruction default, so a tx that
480
+ * consumes more than that (e.g. a program upgrade) fails on the fork even though
481
+ * real execution succeeds. To match live/Squads execution exactly, every replay
482
+ * tx is decoded and re-emitted with the same `SetComputeUnitLimit` an external
483
+ * executor would prepend — using `computeUnits` when set, `DEFAULT_COMPUTE_UNITS`
484
+ * otherwise (mirroring `buildTransactionMessage`/`transactionToInstructions`).
485
+ *
486
+ * Any address-lookup-table compression in the source tx is preserved: the
487
+ * message is re-compressed against the same tables before compiling, so an
488
+ * ALT-heavy tx (e.g. cross-collateral reconciliation) stays under the 1232-byte
489
+ * packet limit instead of being re-emitted with the accounts inlined. The zero
490
+ * DEFAULT_BLOCKHASH is preserved and accepted because the fork runs with
491
+ * `skipBlockhashCheck` and the send uses `skipPreflight`.
492
+ */
493
+ async function buildForkReplayTransaction(rpc, transaction) {
494
+ const wireBytes = base58Encoder.encode(transaction.transaction_base58);
495
+ const decoded = transactionDecoder.decode(wireBytes);
496
+ const units = transaction.computeUnits ?? constants/* DEFAULT_COMPUTE_UNITS */.I1;
497
+ const compiledMessage = compiledMessageDecoder.decode(decoded.messageBytes);
498
+ (0,validation/* assert */.v)(compiledMessage.version !== 1, 'v1 fork replay requires header-based compute budget support');
499
+ const addressLookupTables = await resolveForkLookupTables(rpc, compiledMessage);
500
+ const message = (0,transaction_messages_dist_index_node/* decompileTransactionMessage */.mm)(compiledMessage, {
501
+ addressesByLookupTableAddress: addressLookupTables,
502
+ });
503
+ const withComputeBudget = (0,transaction_messages_dist_index_node/* prependTransactionMessageInstructions */.rR)((0,tx/* getComputeBudgetInstructions */.oR)(units), message);
504
+ if ((0,dist_typeof/* isNullish */.u)(addressLookupTables)) {
505
+ return (0,dist_index_node/* getBase64EncodedWireTransaction */.RO)((0,dist_index_node/* compileTransaction */.i5)(withComputeBudget));
506
+ }
507
+ // Only versioned (v0) messages reference lookup tables, so a defined ALT map
508
+ // implies a non-legacy message; narrow so kit's compressor accepts it.
509
+ (0,validation/* assert */.v)(withComputeBudget.version === 0, 'address-lookup tables require a v0 transaction');
510
+ const recompressed = (0,transaction_messages_dist_index_node/* compressTransactionMessageUsingAddressLookupTables */.Zg)(withComputeBudget, addressLookupTables);
511
+ return (0,dist_index_node/* getBase64EncodedWireTransaction */.RO)((0,dist_index_node/* compileTransaction */.i5)(recompressed));
512
+ }
513
+ /**
514
+ * Ensures the fork airdrops SOL to the fixed fork-only impersonation fee payer
515
+ * at boot, so keyless impersonated applies can pay fees. surfpool airdrops a
516
+ * single amount to every address, so the fee payer is merged into the caller's
517
+ * address list and the amount is raised to at least the impersonation buffer.
518
+ */
519
+ function withImpersonationAirdrop(airdrops) {
520
+ const feePayer = impersonation/* FORK_IMPERSONATION_FEE_PAYER */.P.address;
521
+ if (!airdrops) {
522
+ return {
523
+ addresses: [feePayer],
524
+ lamports: impersonation/* FORK_IMPERSONATION_AIRDROP_LAMPORTS */.X,
525
+ };
526
+ }
527
+ const addresses = airdrops.addresses.includes(feePayer)
528
+ ? airdrops.addresses
529
+ : [...airdrops.addresses, feePayer];
530
+ const lamports = airdrops.lamports > impersonation/* FORK_IMPERSONATION_AIRDROP_LAMPORTS */.X
531
+ ? airdrops.lamports
532
+ : impersonation/* FORK_IMPERSONATION_AIRDROP_LAMPORTS */.X;
533
+ return { addresses, lamports };
534
+ }
535
+ class RunningSvmFork {
536
+ node;
537
+ rpc;
538
+ rpcUrl;
539
+ constructor(node, rpc, rpcUrl) {
540
+ this.node = node;
541
+ this.rpc = rpc;
542
+ this.rpcUrl = rpcUrl;
543
+ }
544
+ }
545
+ async function startSvmFork(config) {
546
+ const runNode = config.runNode ?? runSurfpoolNode;
547
+ const node = await runNode({
548
+ datasource: {
549
+ mode: SurfpoolDatasourceMode.Fork,
550
+ rpcUrl: config.upstreamRpcUrl,
551
+ },
552
+ rpcPort: config.rpcPort,
553
+ wsPort: config.wsPort,
554
+ airdrops: withImpersonationAirdrop(config.airdrops),
555
+ skipSignatureVerification: true,
556
+ skipBlockhashCheck: true,
557
+ image: config.image,
558
+ binaryPath: config.binaryPath,
559
+ keepRunning: config.keepRunning,
560
+ });
561
+ return new RunningSvmFork(node, (0,dist_rpc/* createRpc */.C8)(node.rpcUrl), node.rpcUrl);
562
+ }
563
+ class SvmForkManager {
564
+ config;
565
+ running;
566
+ constructor(config) {
567
+ this.config = config;
568
+ }
569
+ get requireRunning() {
570
+ const running = this.running;
571
+ (0,validation/* assert */.v)(running, `Fork not started for chain ${this.config.chainName}`);
572
+ return running;
573
+ }
574
+ async start() {
575
+ this.running = await startSvmFork(this.config);
576
+ }
577
+ async applyForkConfig(config) {
578
+ const { rpc } = this.requireRunning;
579
+ for (const transaction of config.transactions) {
580
+ await this.submitTransaction(rpc, transaction);
581
+ }
582
+ }
583
+ getForkedChainMetadata() {
584
+ return {
585
+ rpcUrls: [{ http: this.requireRunning.rpcUrl }],
586
+ blocks: { confirmations: 1 },
587
+ };
588
+ }
589
+ kill() {
590
+ this.running?.node.kill();
591
+ }
592
+ async submitTransaction(rpc, transaction) {
593
+ const wireTransaction = await buildForkReplayTransaction(rpc, transaction);
594
+ svm_fork_manager_logger.debug({ annotation: transaction.annotation }, 'replaying transaction against fork');
595
+ const signature = await rpc
596
+ .sendTransaction(wireTransaction, {
597
+ encoding: 'base64',
598
+ skipPreflight: true,
599
+ maxRetries: 0n,
600
+ preflightCommitment: RPC_COMMITMENT,
601
+ })
602
+ .send();
603
+ const status = await (0,dist_async/* pollAsync */.kp)(async () => {
604
+ const { value } = await rpc.getSignatureStatuses([signature]).send();
605
+ const result = value[0];
606
+ (0,validation/* assert */.v)(result, `transaction ${signature} not processed yet`);
607
+ // A failed tx is terminal: resolve immediately so the assert below
608
+ // surfaces the failure instead of polling until the attempts run out.
609
+ if (!(0,dist_typeof/* isNullish */.u)(result.err)) {
610
+ return result;
611
+ }
612
+ // kit 6.x can report `processed` before `confirmed`; wait for the
613
+ // configured commitment so a dependent next tx doesn't race an
614
+ // unconfirmed one.
615
+ const confirmation = result.confirmationStatus;
616
+ (0,validation/* assert */.v)(confirmation === RPC_COMMITMENT || confirmation === 'finalized', `transaction ${signature} not yet ${RPC_COMMITMENT} (status: ${confirmation})`);
617
+ return result;
618
+ }, POLL_INTERVAL_MS, POLL_MAX_ATTEMPTS);
619
+ (0,validation/* assert */.v)((0,dist_typeof/* isNullish */.u)(status.err), `fork replay transaction ${signature} failed: ${JSON.stringify(status.err, (_key, value) => (typeof value === 'bigint' ? value.toString() : value))}`);
620
+ if (transaction.waitForSlotAdvance) {
621
+ const confirmedSlot = status.slot;
622
+ await (0,dist_async/* pollAsync */.kp)(async () => {
623
+ const slot = await rpc.getSlot({ commitment: RPC_COMMITMENT }).send();
624
+ (0,validation/* assert */.v)(slot > confirmedSlot, `slot ${slot} has not advanced past ${confirmedSlot}`);
625
+ }, POLL_INTERVAL_MS, POLL_MAX_ATTEMPTS);
626
+ }
627
+ }
628
+ }
629
+ function createSvmForkManager(config) {
630
+ return new SvmForkManager(config);
631
+ }
632
+ //# sourceMappingURL=svm-fork-manager.js.map
633
+ // EXTERNAL MODULE: ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/schemas.js + 7 modules
634
+ var schemas = __webpack_require__(58228);
635
+ ;// CONCATENATED MODULE: ../svm-sdk/dist/fork/svm-fork-config.js
636
+
637
+ const PrintableSvmTransactionSchema = schemas/* object */.Ik({
638
+ annotation: schemas/* string */.Yj().optional(),
639
+ instructions: schemas/* array */.YO(schemas/* unknown */.L5()).optional(),
640
+ computeUnits: schemas/* number */.ai().optional(),
641
+ transaction_base58: schemas/* string */.Yj(),
642
+ message_base58: schemas/* string */.Yj().optional(),
643
+ waitForSlotAdvance: schemas/* boolean */.zM().optional(),
644
+ });
645
+ const SvmRawForkConfigSchema = schemas/* union */.KC([
646
+ schemas/* object */.Ik({ transactions: schemas/* array */.YO(PrintableSvmTransactionSchema) }),
647
+ schemas/* object */.Ik({ path: schemas/* string */.Yj() }),
648
+ ]);
649
+ /**
650
+ * Parses a per-chain SVM fork-config slice. A `path` reference loads the
651
+ * `warp apply --submitter file` output (a `PrintableSvmTransaction[]`) via the
652
+ * injected file reader; inline `transactions` are used directly.
653
+ */
654
+ function parseSvmForkConfig(raw, fileReader) {
655
+ const parsed = SvmRawForkConfigSchema.parse(raw);
656
+ if ('path' in parsed) {
657
+ const transactions = schemas/* array */.YO(PrintableSvmTransactionSchema)
658
+ .parse(fileReader(parsed.path));
659
+ return { transactions };
660
+ }
661
+ return { transactions: parsed.transactions };
662
+ }
663
+ //# sourceMappingURL=svm-fork-config.js.map
664
+ ;// CONCATENATED MODULE: ../svm-sdk/dist/fork/index.js
665
+
666
+
667
+
668
+ //# sourceMappingURL=index.js.map
669
+
670
+ /***/ })
671
+
672
+ };