prool 0.0.3 → 0.0.5
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 +15 -0
- package/_lib/exports/index.d.ts +1 -1
- package/_lib/exports/processes.d.ts +2 -0
- package/_lib/exports/processes.d.ts.map +1 -0
- package/_lib/exports/processes.js +2 -0
- package/_lib/exports/processes.js.map +1 -0
- package/_lib/instance.d.ts +9 -6
- package/_lib/instance.d.ts.map +1 -1
- package/_lib/instance.js +22 -3
- package/_lib/instance.js.map +1 -1
- package/_lib/instances/anvil.d.ts +1 -5
- package/_lib/instances/anvil.d.ts.map +1 -1
- package/_lib/instances/anvil.js +18 -44
- package/_lib/instances/anvil.js.map +1 -1
- package/_lib/instances/stackup.d.ts +86 -0
- package/_lib/instances/stackup.d.ts.map +1 -0
- package/_lib/instances/stackup.js +89 -0
- package/_lib/instances/stackup.js.map +1 -0
- package/_lib/pool.d.ts +7 -6
- package/_lib/pool.d.ts.map +1 -1
- package/_lib/pool.js +60 -53
- package/_lib/pool.js.map +1 -1
- package/_lib/processes/execa.d.ts +27 -0
- package/_lib/processes/execa.d.ts.map +1 -0
- package/_lib/processes/execa.js +63 -0
- package/_lib/processes/execa.js.map +1 -0
- package/_lib/server.d.ts +3 -3
- package/_lib/server.d.ts.map +1 -1
- package/_lib/server.js +42 -34
- package/_lib/server.js.map +1 -1
- package/_lib/utils.d.ts +4 -3
- package/_lib/utils.d.ts.map +1 -1
- package/_lib/utils.js +2 -2
- package/_lib/utils.js.map +1 -1
- package/exports/index.ts +2 -2
- package/exports/processes.test.ts +10 -0
- package/exports/processes.ts +8 -0
- package/instance.test.ts +34 -2
- package/instance.ts +46 -13
- package/instances/anvil.test.ts +5 -3
- package/instances/anvil.ts +21 -49
- package/instances/stackup.test.ts +106 -0
- package/instances/stackup.ts +162 -0
- package/package.json +6 -2
- package/pool.test.ts +203 -138
- package/pool.ts +83 -66
- package/processes/execa.test.ts +143 -0
- package/processes/execa.ts +100 -0
- package/server.test.ts +162 -85
- package/server.ts +46 -38
- package/tsconfig.build.tsbuildinfo +1 -1
- package/utils.ts +11 -9
package/instance.ts
CHANGED
|
@@ -8,11 +8,11 @@ type EventTypes = {
|
|
|
8
8
|
stdout: [message: string]
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
type InstanceStartOptions_internal = {
|
|
11
|
+
export type InstanceStartOptions_internal = {
|
|
12
12
|
emitter: EventEmitter<EventTypes>
|
|
13
13
|
status: Instance['status']
|
|
14
14
|
}
|
|
15
|
-
type InstanceStopOptions_internal = {
|
|
15
|
+
export type InstanceStopOptions_internal = {
|
|
16
16
|
emitter: EventEmitter<EventTypes>
|
|
17
17
|
status: Instance['status']
|
|
18
18
|
}
|
|
@@ -30,9 +30,10 @@ export type DefineInstanceFn<
|
|
|
30
30
|
> = (parameters: parameters) => Pick<Instance, 'host' | 'name' | 'port'> & {
|
|
31
31
|
_internal?: _internal | undefined
|
|
32
32
|
start(
|
|
33
|
-
options: InstanceStartOptions
|
|
33
|
+
options: InstanceStartOptions,
|
|
34
|
+
options_internal: InstanceStartOptions_internal,
|
|
34
35
|
): Promise<void>
|
|
35
|
-
stop(
|
|
36
|
+
stop(options_internal: InstanceStopOptions_internal): Promise<void>
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export type Instance<
|
|
@@ -75,16 +76,25 @@ export type Instance<
|
|
|
75
76
|
* @example ["Listening on http://127.0.0.1", "Started successfully."]
|
|
76
77
|
*/
|
|
77
78
|
messages: { clear(): void; get(): string[] }
|
|
79
|
+
/**
|
|
80
|
+
* Retarts the instance.
|
|
81
|
+
*/
|
|
82
|
+
restart(): Promise<void>
|
|
78
83
|
/**
|
|
79
84
|
* Status of the instance.
|
|
80
85
|
*
|
|
81
86
|
* @default "idle"
|
|
82
87
|
*/
|
|
83
|
-
status:
|
|
88
|
+
status:
|
|
89
|
+
| 'idle'
|
|
90
|
+
| 'restarting'
|
|
91
|
+
| 'stopped'
|
|
92
|
+
| 'starting'
|
|
93
|
+
| 'started'
|
|
94
|
+
| 'stopping'
|
|
84
95
|
/**
|
|
85
96
|
* Starts the instance.
|
|
86
97
|
*
|
|
87
|
-
* @param options - Options for starting the instance.
|
|
88
98
|
* @returns A function to stop the instance.
|
|
89
99
|
*/
|
|
90
100
|
start(): Promise<() => void>
|
|
@@ -147,8 +157,9 @@ export function defineInstance<
|
|
|
147
157
|
...fn(parameters),
|
|
148
158
|
...createParameters,
|
|
149
159
|
}
|
|
150
|
-
const { messageBuffer = 20, timeout
|
|
160
|
+
const { messageBuffer = 20, timeout } = options
|
|
151
161
|
|
|
162
|
+
let restartResolver = Promise.withResolvers<void>()
|
|
152
163
|
let startResolver = Promise.withResolvers<() => void>()
|
|
153
164
|
let stopResolver = Promise.withResolvers<void>()
|
|
154
165
|
|
|
@@ -156,6 +167,7 @@ export function defineInstance<
|
|
|
156
167
|
|
|
157
168
|
let messages: string[] = []
|
|
158
169
|
let status: Instance['status'] = 'idle'
|
|
170
|
+
let restarting = false
|
|
159
171
|
|
|
160
172
|
function onExit() {
|
|
161
173
|
status = 'stopped'
|
|
@@ -182,6 +194,7 @@ export function defineInstance<
|
|
|
182
194
|
name,
|
|
183
195
|
port,
|
|
184
196
|
get status() {
|
|
197
|
+
if (restarting) return 'restarting'
|
|
185
198
|
return status
|
|
186
199
|
},
|
|
187
200
|
async start() {
|
|
@@ -205,16 +218,20 @@ export function defineInstance<
|
|
|
205
218
|
emitter.on('exit', onExit)
|
|
206
219
|
|
|
207
220
|
status = 'starting'
|
|
208
|
-
start(
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
221
|
+
start(
|
|
222
|
+
{
|
|
223
|
+
port,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
emitter,
|
|
227
|
+
status: this.status,
|
|
228
|
+
},
|
|
229
|
+
)
|
|
213
230
|
.then(() => {
|
|
214
231
|
status = 'started'
|
|
215
232
|
|
|
216
233
|
stopResolver = Promise.withResolvers<void>()
|
|
217
|
-
startResolver.resolve(this.stop)
|
|
234
|
+
startResolver.resolve(this.stop.bind(this))
|
|
218
235
|
})
|
|
219
236
|
.catch((error) => {
|
|
220
237
|
status = 'idle'
|
|
@@ -262,6 +279,22 @@ export function defineInstance<
|
|
|
262
279
|
|
|
263
280
|
return stopResolver.promise
|
|
264
281
|
},
|
|
282
|
+
async restart() {
|
|
283
|
+
if (restarting) return restartResolver.promise
|
|
284
|
+
|
|
285
|
+
restarting = true
|
|
286
|
+
|
|
287
|
+
this.stop()
|
|
288
|
+
.then(() => this.start.bind(this)())
|
|
289
|
+
.then(() => restartResolver.resolve())
|
|
290
|
+
.catch(restartResolver.reject)
|
|
291
|
+
.finally(() => {
|
|
292
|
+
restartResolver = Promise.withResolvers<void>()
|
|
293
|
+
restarting = false
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
return restartResolver.promise
|
|
297
|
+
},
|
|
265
298
|
|
|
266
299
|
addListener: emitter.addListener.bind(emitter),
|
|
267
300
|
off: emitter.off.bind(emitter),
|
package/instances/anvil.test.ts
CHANGED
|
@@ -47,7 +47,7 @@ test('behavior: instance errored (duplicate ports)', async () => {
|
|
|
47
47
|
|
|
48
48
|
await instance_1.start()
|
|
49
49
|
await expect(() => instance_2.start()).rejects.toThrowError(
|
|
50
|
-
'Failed to start anvil',
|
|
50
|
+
'Failed to start process "anvil"',
|
|
51
51
|
)
|
|
52
52
|
})
|
|
53
53
|
|
|
@@ -81,7 +81,9 @@ test('behavior: can subscribe to stderr', async () => {
|
|
|
81
81
|
|
|
82
82
|
await instance_1.start()
|
|
83
83
|
instance_2.on('stderr', (message) => messages.push(message))
|
|
84
|
-
await expect(instance_2.start()).rejects.toThrow(
|
|
84
|
+
await expect(instance_2.start()).rejects.toThrow(
|
|
85
|
+
'Failed to start process "anvil"',
|
|
86
|
+
)
|
|
85
87
|
})
|
|
86
88
|
|
|
87
89
|
test('behavior: starts anvil with custom options', async () => {
|
|
@@ -122,6 +124,6 @@ test('behavior: exit when status is starting', async () => {
|
|
|
122
124
|
instance._internal.process.kill()
|
|
123
125
|
|
|
124
126
|
await expect(promise).rejects.toThrowErrorMatchingInlineSnapshot(
|
|
125
|
-
'[Error: Failed to start anvil: exited.]',
|
|
127
|
+
'[Error: Failed to start process "anvil": exited.]',
|
|
126
128
|
)
|
|
127
129
|
})
|
package/instances/anvil.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type ResultPromise, execa } from 'execa'
|
|
2
1
|
import { defineInstance } from '../instance.js'
|
|
3
|
-
import {
|
|
2
|
+
import { execa } from '../processes/execa.js'
|
|
4
3
|
import { toArgs } from '../utils.js'
|
|
5
4
|
|
|
6
5
|
export type AnvilParameters = {
|
|
@@ -259,64 +258,37 @@ export type AnvilParameters = {
|
|
|
259
258
|
export const anvil = defineInstance((parameters?: AnvilParameters) => {
|
|
260
259
|
const { binary = 'anvil', ...args } = parameters || {}
|
|
261
260
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
async function stop() {
|
|
265
|
-
const killed = process.kill()
|
|
266
|
-
if (!killed) throw new Error('Failed to stop anvil')
|
|
267
|
-
return new Promise((resolve) => process.on('close', resolve))
|
|
268
|
-
}
|
|
261
|
+
const name = 'anvil'
|
|
262
|
+
const process = execa({ name })
|
|
269
263
|
|
|
270
264
|
return {
|
|
271
265
|
_internal: {
|
|
272
266
|
args,
|
|
273
267
|
get process() {
|
|
274
|
-
return process
|
|
268
|
+
return process._internal.process
|
|
275
269
|
},
|
|
276
270
|
},
|
|
277
271
|
host: args.host ?? 'localhost',
|
|
278
|
-
name
|
|
272
|
+
name,
|
|
279
273
|
port: args.port ?? 8545,
|
|
280
|
-
async start({
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
})
|
|
297
|
-
process.stderr.on('data', async (data) => {
|
|
298
|
-
const message = stripColors(data.toString())
|
|
299
|
-
emitter.emit('message', message)
|
|
300
|
-
emitter.emit('stderr', message)
|
|
301
|
-
await stop()
|
|
302
|
-
reject(new Error(`Failed to start anvil: ${data.toString()}`))
|
|
303
|
-
})
|
|
304
|
-
process.on('close', () => process.removeAllListeners())
|
|
305
|
-
process.on('exit', (code, signal) => {
|
|
306
|
-
emitter.emit('exit', code, signal)
|
|
307
|
-
|
|
308
|
-
if (!code) {
|
|
309
|
-
process.removeAllListeners()
|
|
310
|
-
if (status === 'starting')
|
|
311
|
-
reject(new Error('Failed to start anvil: exited.'))
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
return promise
|
|
274
|
+
async start({ port = args.port }, options) {
|
|
275
|
+
return await process.start(
|
|
276
|
+
($) => $`${binary} ${toArgs({ ...args, port })}`,
|
|
277
|
+
{
|
|
278
|
+
...options,
|
|
279
|
+
// Resolve when the process is listening via a "Listening on" message.
|
|
280
|
+
resolver({ process, reject, resolve }) {
|
|
281
|
+
process.stdout.on('data', (data) => {
|
|
282
|
+
const message = data.toString()
|
|
283
|
+
if (message.includes('Listening on')) resolve()
|
|
284
|
+
})
|
|
285
|
+
process.stderr.on('data', reject)
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
)
|
|
316
289
|
},
|
|
317
290
|
async stop() {
|
|
318
|
-
process.
|
|
319
|
-
await stop()
|
|
291
|
+
await process.stop()
|
|
320
292
|
},
|
|
321
293
|
}
|
|
322
294
|
})
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import getPort from 'get-port'
|
|
2
|
+
import { afterEach, beforeAll, expect, test } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { stackupOptions } from '../../test/utils.js'
|
|
5
|
+
import type { Instance } from '../instance.js'
|
|
6
|
+
import { anvil } from './anvil.js'
|
|
7
|
+
import { type StackupParameters, stackup } from './stackup.js'
|
|
8
|
+
|
|
9
|
+
const instances: Instance[] = []
|
|
10
|
+
|
|
11
|
+
const port = await getPort()
|
|
12
|
+
|
|
13
|
+
const defineInstance = (parameters?: Partial<StackupParameters>) => {
|
|
14
|
+
const instance = stackup({
|
|
15
|
+
...stackupOptions({ port }),
|
|
16
|
+
...parameters,
|
|
17
|
+
})
|
|
18
|
+
instances.push(instance)
|
|
19
|
+
return instance
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
beforeAll(() => anvil({ port }).start())
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
for (const instance of instances) await instance.stop().catch(() => {})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('default', async () => {
|
|
29
|
+
const messages: string[] = []
|
|
30
|
+
const stdouts: string[] = []
|
|
31
|
+
|
|
32
|
+
const instance = defineInstance()
|
|
33
|
+
|
|
34
|
+
instance.on('message', (m) => messages.push(m))
|
|
35
|
+
instance.on('stdout', (m) => stdouts.push(m))
|
|
36
|
+
|
|
37
|
+
expect(instance.messages.get()).toMatchInlineSnapshot('[]')
|
|
38
|
+
|
|
39
|
+
await instance.start()
|
|
40
|
+
expect(instance.status).toEqual('started')
|
|
41
|
+
|
|
42
|
+
expect(messages.join('')).toBeDefined()
|
|
43
|
+
expect(stdouts.join('')).toBeDefined()
|
|
44
|
+
expect(instance.messages.get().join('')).toBeDefined()
|
|
45
|
+
|
|
46
|
+
await instance.stop()
|
|
47
|
+
expect(instance.status).toEqual('stopped')
|
|
48
|
+
|
|
49
|
+
expect(messages.join('')).toBeDefined()
|
|
50
|
+
expect(stdouts.join('')).toBeDefined()
|
|
51
|
+
expect(instance.messages.get()).toMatchInlineSnapshot('[]')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('behavior: instance errored (duplicate ports)', async () => {
|
|
55
|
+
const instance_1 = defineInstance({
|
|
56
|
+
port: 1337,
|
|
57
|
+
})
|
|
58
|
+
const instance_2 = defineInstance({
|
|
59
|
+
port: 1337,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
await instance_1.start()
|
|
63
|
+
await expect(() => instance_2.start()).rejects.toThrowError()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('behavior: start and stop multiple times', async () => {
|
|
67
|
+
const instance = defineInstance()
|
|
68
|
+
|
|
69
|
+
await instance.start()
|
|
70
|
+
await instance.stop()
|
|
71
|
+
await instance.start()
|
|
72
|
+
await instance.stop()
|
|
73
|
+
await instance.start()
|
|
74
|
+
await instance.stop()
|
|
75
|
+
await instance.start()
|
|
76
|
+
await instance.stop()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
test('behavior: can subscribe to stderr', async () => {
|
|
80
|
+
const messages: string[] = []
|
|
81
|
+
|
|
82
|
+
const instance_1 = defineInstance({ port: 1337 })
|
|
83
|
+
const instance_2 = defineInstance({ port: 1337 })
|
|
84
|
+
|
|
85
|
+
await instance_1.start()
|
|
86
|
+
instance_2.on('stderr', (message) => messages.push(message))
|
|
87
|
+
await expect(instance_2.start()).rejects.toThrowError()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('behavior: exit', async () => {
|
|
91
|
+
const instance = defineInstance()
|
|
92
|
+
|
|
93
|
+
let exitCode: number | null | undefined = undefined
|
|
94
|
+
instance.on('exit', (code) => {
|
|
95
|
+
exitCode = code
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
await instance.start()
|
|
99
|
+
expect(instance.status).toEqual('started')
|
|
100
|
+
|
|
101
|
+
instance._internal.process.kill()
|
|
102
|
+
|
|
103
|
+
await new Promise<void>((res) => setTimeout(res, 100))
|
|
104
|
+
expect(instance.status).toEqual('stopped')
|
|
105
|
+
expect(typeof exitCode !== 'undefined').toBeTruthy()
|
|
106
|
+
})
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { defineInstance } from '../instance.js'
|
|
2
|
+
import { execa } from '../processes/execa.js'
|
|
3
|
+
|
|
4
|
+
export type StackupParameters = {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the native tracer to use during validation. This will be "bundlerCollectorTracer" if using builds from ERC-4337 execution client repo.
|
|
7
|
+
* Defaults to address of `privateKey`.
|
|
8
|
+
*/
|
|
9
|
+
beneficiary?: string | undefined
|
|
10
|
+
/**
|
|
11
|
+
* Directory to store the embedded database.
|
|
12
|
+
* @default /tmp/stackup_bundler
|
|
13
|
+
*/
|
|
14
|
+
dataDirectory?: string | undefined
|
|
15
|
+
/**
|
|
16
|
+
* RPC url to the execution client.
|
|
17
|
+
*/
|
|
18
|
+
ethClientUrl: string
|
|
19
|
+
/**
|
|
20
|
+
* A boolean value for bundlers on an Arbitrum stack network to properly account for the L1 callData cost.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
isArbStackNetwork?: boolean | undefined
|
|
24
|
+
/**
|
|
25
|
+
* A boolean value for bundlers on an OP stack network to properly account for the L1 callData cost.
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
isOpStackNetwork?: boolean | undefined
|
|
29
|
+
/**
|
|
30
|
+
* A boolean value for bundlers on a network that supports RIP-7212 precompile for secp256r1 signature verification.
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
isRip7212Supported?: boolean | undefined
|
|
34
|
+
/**
|
|
35
|
+
* The maximum gas limit that can be submitted per UserOperation batch.
|
|
36
|
+
* @default 18_000_000
|
|
37
|
+
*/
|
|
38
|
+
maxBatchGasLimit?: number | undefined
|
|
39
|
+
/**
|
|
40
|
+
* The maximum duration that a userOp can stay in the mempool before getting dropped.
|
|
41
|
+
* @default 180
|
|
42
|
+
*/
|
|
43
|
+
maxOpTtlSeconds?: number | undefined
|
|
44
|
+
/**
|
|
45
|
+
* The maximum verificationGasLimit on a received UserOperation.
|
|
46
|
+
* @default 6_000_000
|
|
47
|
+
*/
|
|
48
|
+
maxVerificationGas?: number | undefined
|
|
49
|
+
/**
|
|
50
|
+
* The maximum block range when looking up a User Operation with eth_getUserOperationReceipt or eth_getUserOperationByHash.
|
|
51
|
+
*
|
|
52
|
+
* Higher limits allow for fetching older User Operations but will result in higher request latency due to additional compute on the underlying node.
|
|
53
|
+
*
|
|
54
|
+
* @default 2_000
|
|
55
|
+
*/
|
|
56
|
+
opLookupLimit?: number | undefined
|
|
57
|
+
/**
|
|
58
|
+
* Port to start the instance on.
|
|
59
|
+
*/
|
|
60
|
+
port?: number | undefined
|
|
61
|
+
/**
|
|
62
|
+
* The private key for the EOA used to relay User Operation bundles to the EntryPoint.
|
|
63
|
+
*/
|
|
64
|
+
privateKey: string
|
|
65
|
+
/**
|
|
66
|
+
* EntryPoint addresses to support. The first address is the preferred EntryPoint.
|
|
67
|
+
*/
|
|
68
|
+
supportedEntryPoints?: string[]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Defines an Anvil instance.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const instance = stackup({
|
|
77
|
+
* ethClientUrl: 'http://localhost:8545',
|
|
78
|
+
* port: 4337,
|
|
79
|
+
* privateKey: '0x...'
|
|
80
|
+
* })
|
|
81
|
+
* await instance.start()
|
|
82
|
+
* // ...
|
|
83
|
+
* await instance.stop()
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export const stackup = defineInstance((parameters?: StackupParameters) => {
|
|
87
|
+
const args = (parameters || {}) as StackupParameters
|
|
88
|
+
|
|
89
|
+
const host = 'localhost'
|
|
90
|
+
const name = 'stackup'
|
|
91
|
+
const process = execa({ name })
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
_internal: {
|
|
95
|
+
args,
|
|
96
|
+
get process() {
|
|
97
|
+
return process._internal.process
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
host,
|
|
101
|
+
name,
|
|
102
|
+
port: args.port ?? 4337,
|
|
103
|
+
async start({ port = args.port }, options) {
|
|
104
|
+
const args_ = [
|
|
105
|
+
'--net',
|
|
106
|
+
'host',
|
|
107
|
+
'--add-host',
|
|
108
|
+
'host.docker.internal:host-gateway',
|
|
109
|
+
'--add-host',
|
|
110
|
+
'localhost:host-gateway',
|
|
111
|
+
'-p',
|
|
112
|
+
`${port}:${port}`,
|
|
113
|
+
'-e',
|
|
114
|
+
`ERC4337_BUNDLER_PORT=${port}`,
|
|
115
|
+
...Object.entries(args).flatMap(([key, value]) => {
|
|
116
|
+
if (key === 'port') return []
|
|
117
|
+
if (value === undefined) return []
|
|
118
|
+
|
|
119
|
+
if (key === 'ethClientUrl')
|
|
120
|
+
value = (value as string).replaceAll(
|
|
121
|
+
/127\.0\.0\.1|0\.0\.0\.0/g,
|
|
122
|
+
'host.docker.internal',
|
|
123
|
+
)
|
|
124
|
+
if (key === 'privateKey') value = (value as string).replace('0x', '')
|
|
125
|
+
|
|
126
|
+
return [
|
|
127
|
+
'-e',
|
|
128
|
+
`ERC4337_BUNDLER_${key
|
|
129
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
130
|
+
.toUpperCase()}=${value}`,
|
|
131
|
+
]
|
|
132
|
+
}),
|
|
133
|
+
'stackupwallet/stackup-bundler:latest',
|
|
134
|
+
'/app/stackup-bundler',
|
|
135
|
+
'start',
|
|
136
|
+
'--mode',
|
|
137
|
+
'private',
|
|
138
|
+
]
|
|
139
|
+
return await process.start(($) => $`docker run ${args_}`, {
|
|
140
|
+
...options,
|
|
141
|
+
resolver({ process, resolve, reject }) {
|
|
142
|
+
process.stderr.on('data', async (data) => {
|
|
143
|
+
const message = data.toString()
|
|
144
|
+
// For some reason, `stackup-bundler` logs to stderr. So we have to try
|
|
145
|
+
// and dissect what is an error, and what is not. 😅
|
|
146
|
+
if (message.includes('Set nextTxnTs to'))
|
|
147
|
+
setTimeout(() => resolve(), 100)
|
|
148
|
+
else if (
|
|
149
|
+
message
|
|
150
|
+
.toLowerCase()
|
|
151
|
+
.match(/panic|error|connection refused|address already in use/)
|
|
152
|
+
)
|
|
153
|
+
reject(data)
|
|
154
|
+
})
|
|
155
|
+
},
|
|
156
|
+
})
|
|
157
|
+
},
|
|
158
|
+
async stop() {
|
|
159
|
+
await process.stop()
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prool",
|
|
3
|
-
"description": "",
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"description": "HTTP testing instances for Ethereum",
|
|
4
|
+
"version": "0.0.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "_lib/exports/index.mjs",
|
|
7
7
|
"types": "_lib/exports/index.d.ts",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"types": "./_lib/exports/index.d.ts",
|
|
16
16
|
"default": "./_lib/exports/index.js"
|
|
17
17
|
},
|
|
18
|
+
"./processes": {
|
|
19
|
+
"types": "./_lib/exports/processes.d.ts",
|
|
20
|
+
"default": "./_lib/exports/processes.js"
|
|
21
|
+
},
|
|
18
22
|
"./instances": {
|
|
19
23
|
"types": "./_lib/exports/instances.d.ts",
|
|
20
24
|
"default": "./_lib/exports/instances.js"
|