@nomicfoundation/edr 0.12.0-next.8 → 0.12.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.
Files changed (52) hide show
  1. package/coverage.sol +38 -0
  2. package/dist/src/ts/coverage.d.ts +6 -0
  3. package/dist/src/ts/coverage.d.ts.map +1 -0
  4. package/dist/src/ts/coverage.js +51 -0
  5. package/dist/src/ts/coverage.js.map +1 -0
  6. package/index.d.ts +267 -27
  7. package/index.js +5 -2
  8. package/package.json +23 -12
  9. package/src/account.rs +0 -124
  10. package/src/block.rs +0 -28
  11. package/src/call_override.rs +0 -116
  12. package/src/cast.rs +0 -165
  13. package/src/chains/generic.rs +0 -58
  14. package/src/chains/l1.rs +0 -268
  15. package/src/chains/op.rs +0 -424
  16. package/src/chains.rs +0 -7
  17. package/src/config.rs +0 -700
  18. package/src/context.rs +0 -447
  19. package/src/contract_decoder.rs +0 -57
  20. package/src/debug_trace.rs +0 -40
  21. package/src/gas_report.rs +0 -92
  22. package/src/instrument.rs +0 -109
  23. package/src/lib.rs +0 -50
  24. package/src/log.rs +0 -28
  25. package/src/logger.rs +0 -120
  26. package/src/mock/time.rs +0 -134
  27. package/src/mock.rs +0 -71
  28. package/src/precompile.rs +0 -50
  29. package/src/provider/factory.rs +0 -22
  30. package/src/provider/response.rs +0 -73
  31. package/src/provider.rs +0 -162
  32. package/src/result.rs +0 -212
  33. package/src/scenarios.rs +0 -53
  34. package/src/serde.rs +0 -57
  35. package/src/solidity_tests/artifact.rs +0 -184
  36. package/src/solidity_tests/config.rs +0 -793
  37. package/src/solidity_tests/factory.rs +0 -22
  38. package/src/solidity_tests/l1.rs +0 -68
  39. package/src/solidity_tests/op.rs +0 -69
  40. package/src/solidity_tests/runner.rs +0 -51
  41. package/src/solidity_tests/test_results.rs +0 -736
  42. package/src/solidity_tests.rs +0 -56
  43. package/src/subscription.rs +0 -32
  44. package/src/trace/debug.rs +0 -61
  45. package/src/trace/exit.rs +0 -89
  46. package/src/trace/library_utils.rs +0 -11
  47. package/src/trace/model.rs +0 -59
  48. package/src/trace/return_data.rs +0 -96
  49. package/src/trace/solidity_stack_trace.rs +0 -869
  50. package/src/trace.rs +0 -199
  51. package/src/ts/solidity_tests.ts +0 -46
  52. package/src/withdrawal.rs +0 -49
@@ -1,793 +0,0 @@
1
- use std::{collections::HashMap, path::PathBuf};
2
-
3
- use derive_more::Debug;
4
- use edr_primitives::hex;
5
- use edr_solidity_tests::{
6
- executors::invariant::InvariantConfig,
7
- fuzz::FuzzConfig,
8
- inspectors::cheatcodes::{CheatsConfigOptions, ExecutionContextConfig},
9
- TestFilterConfig,
10
- };
11
- use foundry_cheatcodes::{FsPermissions, RpcEndpoint, RpcEndpoints};
12
- use napi::{
13
- bindgen_prelude::{BigInt, Uint8Array},
14
- tokio::runtime,
15
- Either, Status,
16
- };
17
- use napi_derive::napi;
18
-
19
- use crate::{
20
- account::AccountOverride,
21
- cast::TryCast,
22
- config::ObservabilityConfig,
23
- serde::{
24
- serialize_optional_bigint_as_struct, serialize_optional_uint8array_as_hex,
25
- serialize_uint8array_as_hex,
26
- },
27
- };
28
-
29
- /// Solidity test runner configuration arguments exposed through the ffi.
30
- /// Docs based on <https://book.getfoundry.sh/reference/config/testing>.
31
- #[napi(object)]
32
- #[derive(Debug, serde::Serialize)]
33
- pub struct SolidityTestRunnerConfigArgs {
34
- /// The absolute path to the project root directory.
35
- /// Relative paths in cheat codes are resolved against this path.
36
- pub project_root: String,
37
- /// Configures the permissions of cheat codes that access the file system.
38
- pub fs_permissions: Option<Vec<PathPermission>>,
39
- /// Whether to support the `testFail` prefix. Defaults to false.
40
- pub test_fail: Option<bool>,
41
- /// Address labels for traces. Defaults to none.
42
- pub labels: Option<Vec<AddressLabel>>,
43
- /// Whether to enable isolation of calls. In isolation mode all top-level
44
- /// calls are executed as a separate transaction in a separate EVM
45
- /// context, enabling more precise gas accounting and transaction state
46
- /// changes.
47
- /// Defaults to false.
48
- pub isolate: Option<bool>,
49
- /// Whether or not to enable the ffi cheatcode.
50
- /// Warning: Enabling this cheatcode has security implications, as it allows
51
- /// tests to execute arbitrary programs on your computer.
52
- /// Defaults to false.
53
- pub ffi: Option<bool>,
54
- /// Allow expecting reverts with `expectRevert` at the same callstack depth
55
- /// as the test. Defaults to false.
56
- pub allow_internal_expect_revert: Option<bool>,
57
- /// The value of `msg.sender` in tests as hex string.
58
- /// Defaults to `0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38`.
59
- #[debug("{:?}", sender.as_ref().map(hex::encode))]
60
- #[serde(serialize_with = "serialize_optional_uint8array_as_hex")]
61
- pub sender: Option<Uint8Array>,
62
- /// The value of `tx.origin` in tests as hex string.
63
- /// Defaults to `0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38`.
64
- #[debug("{:?}", tx_origin.as_ref().map(hex::encode))]
65
- #[serde(serialize_with = "serialize_optional_uint8array_as_hex")]
66
- pub tx_origin: Option<Uint8Array>,
67
- /// The initial balance of the sender in tests.
68
- /// Defaults to `0xffffffffffffffffffffffff`.
69
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
70
- pub initial_balance: Option<BigInt>,
71
- /// The value of `block.number` in tests.
72
- /// Defaults to `1`.
73
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
74
- pub block_number: Option<BigInt>,
75
- /// The value of the `chainid` opcode in tests.
76
- /// Defaults to `31337`.
77
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
78
- pub chain_id: Option<BigInt>,
79
- /// The gas limit for each test case.
80
- /// Defaults to `9_223_372_036_854_775_807` (`i64::MAX`).
81
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
82
- pub gas_limit: Option<BigInt>,
83
- /// The price of gas (in wei) in tests.
84
- /// Defaults to `0`.
85
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
86
- pub gas_price: Option<BigInt>,
87
- /// The base fee per gas (in wei) in tests.
88
- /// Defaults to `0`.
89
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
90
- pub block_base_fee_per_gas: Option<BigInt>,
91
- /// The value of `block.coinbase` in tests.
92
- /// Defaults to `0x0000000000000000000000000000000000000000`.
93
- #[serde(serialize_with = "serialize_optional_uint8array_as_hex")]
94
- #[debug("{:?}", block_coinbase.as_ref().map(hex::encode))]
95
- pub block_coinbase: Option<Uint8Array>,
96
- /// The value of `block.timestamp` in tests.
97
- /// Defaults to 1.
98
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
99
- pub block_timestamp: Option<BigInt>,
100
- /// The value of `block.difficulty` in tests.
101
- /// Defaults to 0.
102
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
103
- pub block_difficulty: Option<BigInt>,
104
- /// The `block.gaslimit` value during EVM execution.
105
- /// Defaults to none.
106
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
107
- pub block_gas_limit: Option<BigInt>,
108
- /// Whether to disable the block gas limit.
109
- /// Defaults to false.
110
- pub disable_block_gas_limit: Option<bool>,
111
- /// The memory limit of the EVM in bytes.
112
- /// Defaults to `33_554_432` (2^25 = 32MiB).
113
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
114
- pub memory_limit: Option<BigInt>,
115
- /// The predeploys applied in local mode. Defaults to no predeploys.
116
- /// These should match the predeploys of the network in fork mode, so they
117
- /// aren't set in fork mode.
118
- /// The code must be set and non-empty. The nonce and the balance default to
119
- /// zero and storage defaults to empty.
120
- pub local_predeploys: Option<Vec<AccountOverride>>,
121
- /// If set, all tests are run in fork mode using this url or remote name.
122
- /// Defaults to none.
123
- pub eth_rpc_url: Option<String>,
124
- /// Pins the block number for the global state fork.
125
- #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
126
- pub fork_block_number: Option<BigInt>,
127
- /// Map of RPC endpoints from chain name to RPC urls for fork cheat codes,
128
- /// e.g. `{ "optimism": "https://optimism.alchemyapi.io/v2/..." }`
129
- pub rpc_endpoints: Option<HashMap<String, String>>,
130
- /// Optional RPC cache path. If this is none, then no RPC calls will be
131
- /// cached, otherwise data is cached to `<rpc_cache_path>/<chain
132
- /// id>/<block number>`. Caching can be disabled for specific chains
133
- /// with `rpc_storage_caching`.
134
- pub rpc_cache_path: Option<String>,
135
- /// What RPC endpoints are cached. Defaults to all.
136
- pub rpc_storage_caching: Option<StorageCachingConfig>,
137
- /// The number of seconds to wait before `vm.prompt` reverts with a timeout.
138
- /// Defaults to 120.
139
- pub prompt_timeout: Option<u32>,
140
- /// Fuzz testing configuration.
141
- pub fuzz: Option<FuzzConfigArgs>,
142
- /// Invariant testing configuration.
143
- /// If an invariant config setting is not set, but a corresponding fuzz
144
- /// config value is set, then the fuzz config value will be used.
145
- pub invariant: Option<InvariantConfigArgs>,
146
- /// Whether to collect stack traces.
147
- pub collect_stack_traces: Option<CollectStackTraces>,
148
- /// Controls which test results should include execution traces. Defaults to
149
- /// None.
150
- pub include_traces: Option<IncludeTraces>,
151
- /// The configuration for the Solidity test runner's observability
152
- #[debug(skip)]
153
- #[serde(skip)]
154
- pub observability: Option<ObservabilityConfig>,
155
- /// A regex pattern to filter tests. If provided, only test methods that
156
- /// match the pattern will be executed and reported as a test result.
157
- pub test_pattern: Option<String>,
158
- /// Controls whether to generate a gas report after running the tests.
159
- /// Enabling this also enables collection of all traces and EVM isolation
160
- /// mode.
161
- /// Defaults to false.
162
- pub generate_gas_report: Option<bool>,
163
- }
164
-
165
- impl SolidityTestRunnerConfigArgs {
166
- /// Resolves the instance, converting it to a
167
- /// [`edr_napi_core::solidity::config::TestRunnerConfig`].
168
- pub fn resolve(
169
- self,
170
- env: &napi::Env,
171
- runtime: runtime::Handle,
172
- ) -> napi::Result<edr_napi_core::solidity::config::TestRunnerConfig> {
173
- let SolidityTestRunnerConfigArgs {
174
- project_root,
175
- fs_permissions,
176
- test_fail,
177
- labels,
178
- isolate,
179
- ffi,
180
- allow_internal_expect_revert,
181
- sender,
182
- tx_origin,
183
- initial_balance,
184
- block_number,
185
- chain_id,
186
- gas_limit,
187
- gas_price,
188
- block_base_fee_per_gas,
189
- block_coinbase,
190
- block_timestamp,
191
- block_difficulty,
192
- block_gas_limit,
193
- disable_block_gas_limit,
194
- memory_limit,
195
- local_predeploys,
196
- eth_rpc_url,
197
- rpc_cache_path,
198
- fork_block_number,
199
- rpc_endpoints,
200
- rpc_storage_caching,
201
- prompt_timeout,
202
- fuzz,
203
- invariant,
204
- collect_stack_traces,
205
- include_traces,
206
- observability,
207
- test_pattern,
208
- generate_gas_report,
209
- } = self;
210
-
211
- let test_pattern = TestFilterConfig {
212
- test_pattern: test_pattern
213
- .as_ref()
214
- .map(|p| {
215
- p.parse()
216
- .map_err(|error| napi::Error::new(Status::InvalidArg, error))
217
- })
218
- .transpose()?,
219
- };
220
-
221
- let local_predeploys = local_predeploys
222
- .map(|local_predeploys| {
223
- local_predeploys
224
- .into_iter()
225
- .map(TryInto::try_into)
226
- .collect::<Result<Vec<_>, _>>()
227
- })
228
- .transpose()?;
229
-
230
- let invariant: InvariantConfig = fuzz
231
- .as_ref()
232
- .map(|f| invariant.clone().unwrap_or_default().defaults_from_fuzz(f))
233
- .or(invariant)
234
- .map(TryFrom::try_from)
235
- .transpose()?
236
- .unwrap_or_default();
237
-
238
- let fuzz: FuzzConfig = fuzz.map(TryFrom::try_from).transpose()?.unwrap_or_default();
239
-
240
- let cheatcode = CheatsConfigOptions {
241
- // TODO https://github.com/NomicFoundation/edr/issues/657
242
- // If gas reporting or coverage is supported, take that into account here.
243
- execution_context: ExecutionContextConfig::Test,
244
- rpc_endpoints: rpc_endpoints
245
- .map(|endpoints| {
246
- RpcEndpoints::new(
247
- endpoints
248
- .into_iter()
249
- .map(|(chain, url)| (chain, RpcEndpoint::Url(url))),
250
- )
251
- })
252
- .unwrap_or_default(),
253
- rpc_cache_path: rpc_cache_path.map(PathBuf::from),
254
- rpc_storage_caching: rpc_storage_caching
255
- .map(TryFrom::try_from)
256
- .transpose()?
257
- .unwrap_or_default(),
258
- fs_permissions: FsPermissions::new(
259
- fs_permissions
260
- .unwrap_or_default()
261
- .into_iter()
262
- .map(Into::into),
263
- ),
264
- prompt_timeout: prompt_timeout.map_or(120, Into::into),
265
- labels: labels
266
- .unwrap_or_default()
267
- .into_iter()
268
- .map(|AddressLabel { address, label }| Ok((address.try_cast()?, label)))
269
- .collect::<Result<_, napi::Error>>()?,
270
- allow_internal_expect_revert: allow_internal_expect_revert.unwrap_or(false),
271
- };
272
-
273
- let on_collected_coverage_fn = observability.map_or_else(
274
- || Ok(None),
275
- |observability| {
276
- observability
277
- .resolve(env, runtime)
278
- .map(|config| config.on_collected_coverage_fn)
279
- },
280
- )?;
281
-
282
- let config = edr_napi_core::solidity::config::TestRunnerConfig {
283
- project_root: project_root.into(),
284
- include_traces: include_traces.unwrap_or_default().into(),
285
- test_fail: test_fail.unwrap_or_default(),
286
- isolate,
287
- ffi,
288
- sender: sender.map(TryCast::try_cast).transpose()?,
289
- tx_origin: tx_origin.map(TryCast::try_cast).transpose()?,
290
- initial_balance: initial_balance.map(TryCast::try_cast).transpose()?,
291
- block_number: block_number.map(TryCast::try_cast).transpose()?,
292
- chain_id: chain_id.map(TryCast::try_cast).transpose()?,
293
- gas_limit: gas_limit.map(TryCast::try_cast).transpose()?,
294
- gas_price: gas_price.map(TryCast::try_cast).transpose()?,
295
- block_base_fee_per_gas: block_base_fee_per_gas.map(TryCast::try_cast).transpose()?,
296
- block_coinbase: block_coinbase.map(TryCast::try_cast).transpose()?,
297
- block_timestamp: block_timestamp.map(TryCast::try_cast).transpose()?,
298
- block_difficulty: block_difficulty.map(TryCast::try_cast).transpose()?,
299
- block_gas_limit: block_gas_limit.map(TryCast::try_cast).transpose()?,
300
- disable_block_gas_limit,
301
- memory_limit: memory_limit.map(TryCast::try_cast).transpose()?,
302
- local_predeploys,
303
- fork_url: eth_rpc_url,
304
- fork_block_number: fork_block_number.map(TryCast::try_cast).transpose()?,
305
- cheatcode,
306
- fuzz,
307
- invariant,
308
- collect_stack_traces: collect_stack_traces.map_or(
309
- edr_solidity_tests::CollectStackTraces::OnFailure,
310
- edr_solidity_tests::CollectStackTraces::from,
311
- ),
312
- on_collected_coverage_fn,
313
- test_pattern,
314
- generate_gas_report,
315
- };
316
-
317
- Ok(config)
318
- }
319
- }
320
-
321
- /// Fuzz testing configuration
322
- #[napi(object)]
323
- #[derive(Clone, Default, Debug, serde::Serialize)]
324
- pub struct FuzzConfigArgs {
325
- /// Path where fuzz failures are recorded and replayed if set.
326
- pub failure_persist_dir: Option<String>,
327
- /// Name of the file to record fuzz failures, defaults to `failures`.
328
- pub failure_persist_file: Option<String>,
329
- /// The amount of fuzz runs to perform for each fuzz test case. Higher
330
- /// values gives more confidence in results at the cost of testing
331
- /// speed.
332
- /// Defaults to 256.
333
- pub runs: Option<u32>,
334
- /// The maximum number of combined inputs that may be rejected before the
335
- /// test as a whole aborts. “Global” filters apply to the whole test
336
- /// case. If the test case is rejected, the whole thing is regenerated.
337
- /// Defaults to 65536.
338
- pub max_test_rejects: Option<u32>,
339
- /// Hexadecimal string.
340
- /// Optional seed for the fuzzing RNG algorithm.
341
- /// Defaults to None.
342
- pub seed: Option<String>,
343
- /// Integer between 0 and 100.
344
- /// The weight of the dictionary. A higher dictionary weight will bias the
345
- /// fuzz inputs towards “interesting” values, e.g. boundary values like
346
- /// type(uint256).max or contract addresses from your environment.
347
- /// Defaults to 40.
348
- pub dictionary_weight: Option<u32>,
349
- /// The flag indicating whether to include values from storage.
350
- /// Defaults to true.
351
- pub include_storage: Option<bool>,
352
- /// The flag indicating whether to include push bytes values.
353
- /// Defaults to true.
354
- pub include_push_bytes: Option<bool>,
355
- }
356
-
357
- impl TryFrom<FuzzConfigArgs> for FuzzConfig {
358
- type Error = napi::Error;
359
-
360
- fn try_from(value: FuzzConfigArgs) -> Result<Self, Self::Error> {
361
- let FuzzConfigArgs {
362
- failure_persist_dir,
363
- failure_persist_file,
364
- runs,
365
- max_test_rejects,
366
- seed,
367
- dictionary_weight,
368
- include_storage,
369
- include_push_bytes,
370
- } = value;
371
-
372
- let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
373
- let failure_persist_file = failure_persist_file.unwrap_or("failures".to_string());
374
- let seed = seed
375
- .map(|s| {
376
- s.parse().map_err(|_err| {
377
- napi::Error::new(Status::InvalidArg, format!("Invalid seed value: {s}"))
378
- })
379
- })
380
- .transpose()?;
381
-
382
- let mut fuzz = FuzzConfig {
383
- seed,
384
- failure_persist_dir,
385
- failure_persist_file,
386
- // TODO https://github.com/NomicFoundation/edr/issues/657
387
- gas_report_samples: 0,
388
- ..FuzzConfig::default()
389
- };
390
-
391
- if let Some(runs) = runs {
392
- fuzz.runs = runs;
393
- }
394
-
395
- if let Some(max_test_rejects) = max_test_rejects {
396
- fuzz.max_test_rejects = max_test_rejects;
397
- }
398
-
399
- if let Some(dictionary_weight) = dictionary_weight {
400
- fuzz.dictionary.dictionary_weight = dictionary_weight;
401
- }
402
-
403
- if let Some(include_storage) = include_storage {
404
- fuzz.dictionary.include_storage = include_storage;
405
- }
406
-
407
- if let Some(include_push_bytes) = include_push_bytes {
408
- fuzz.dictionary.include_push_bytes = include_push_bytes;
409
- }
410
-
411
- Ok(fuzz)
412
- }
413
- }
414
-
415
- impl SolidityTestRunnerConfigArgs {
416
- pub fn try_get_test_filter(&self) -> napi::Result<TestFilterConfig> {
417
- let test_pattern = self
418
- .test_pattern
419
- .as_ref()
420
- .map(|p| {
421
- p.parse()
422
- .map_err(|e| napi::Error::new(Status::InvalidArg, e))
423
- })
424
- .transpose()?;
425
- Ok(TestFilterConfig { test_pattern })
426
- }
427
- }
428
-
429
- /// Invariant testing configuration.
430
- #[napi(object)]
431
- #[derive(Clone, Default, Debug, serde::Serialize)]
432
- pub struct InvariantConfigArgs {
433
- /// Path where invariant failures are recorded and replayed if set.
434
- pub failure_persist_dir: Option<String>,
435
- /// The number of runs that must execute for each invariant test group.
436
- /// Defaults to 256.
437
- pub runs: Option<u32>,
438
- /// The number of calls executed to attempt to break invariants in one run.
439
- /// Defaults to 500.
440
- pub depth: Option<u32>,
441
- /// Fails the invariant fuzzing if a revert occurs.
442
- /// Defaults to false.
443
- pub fail_on_revert: Option<bool>,
444
- /// Overrides unsafe external calls when running invariant tests, useful for
445
- /// e.g. performing reentrancy checks.
446
- /// Defaults to false.
447
- pub call_override: Option<bool>,
448
- /// Integer between 0 and 100.
449
- /// The weight of the dictionary. A higher dictionary weight will bias the
450
- /// fuzz inputs towards “interesting” values, e.g. boundary values like
451
- /// type(uint256).max or contract addresses from your environment.
452
- /// Defaults to 40.
453
- pub dictionary_weight: Option<u32>,
454
- /// The flag indicating whether to include values from storage.
455
- /// Defaults to true.
456
- pub include_storage: Option<bool>,
457
- /// The flag indicating whether to include push bytes values.
458
- /// Defaults to true.
459
- pub include_push_bytes: Option<bool>,
460
- /// The maximum number of attempts to shrink a failed the sequence. Shrink
461
- /// process is disabled if set to 0.
462
- /// Defaults to 5000.
463
- pub shrink_run_limit: Option<u32>,
464
- }
465
-
466
- impl InvariantConfigArgs {
467
- /// Fill in fields from the fuzz config if they are not set.
468
- fn defaults_from_fuzz(mut self, fuzz: &FuzzConfigArgs) -> Self {
469
- let FuzzConfigArgs {
470
- failure_persist_dir,
471
- runs,
472
- dictionary_weight,
473
- include_storage,
474
- include_push_bytes,
475
- // These aren't used in the invariant config.
476
- failure_persist_file: _,
477
- max_test_rejects: _,
478
- seed: _,
479
- } = fuzz;
480
-
481
- if self.failure_persist_dir.is_none() {
482
- self.failure_persist_dir.clone_from(failure_persist_dir);
483
- }
484
-
485
- if self.runs.is_none() {
486
- self.runs = *runs;
487
- }
488
-
489
- if self.dictionary_weight.is_none() {
490
- self.dictionary_weight = *dictionary_weight;
491
- }
492
-
493
- if self.include_storage.is_none() {
494
- self.include_storage = *include_storage;
495
- }
496
-
497
- if self.include_push_bytes.is_none() {
498
- self.include_push_bytes = *include_push_bytes;
499
- }
500
-
501
- self
502
- }
503
- }
504
-
505
- impl From<InvariantConfigArgs> for InvariantConfig {
506
- fn from(value: InvariantConfigArgs) -> Self {
507
- let InvariantConfigArgs {
508
- failure_persist_dir,
509
- runs,
510
- depth,
511
- fail_on_revert,
512
- call_override,
513
- dictionary_weight,
514
- include_storage,
515
- include_push_bytes,
516
- shrink_run_limit,
517
- } = value;
518
-
519
- let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
520
-
521
- let mut invariant = InvariantConfig {
522
- failure_persist_dir,
523
- // TODO https://github.com/NomicFoundation/edr/issues/657
524
- gas_report_samples: 0,
525
- ..InvariantConfig::default()
526
- };
527
-
528
- if let Some(runs) = runs {
529
- invariant.runs = runs;
530
- }
531
-
532
- if let Some(depth) = depth {
533
- invariant.depth = depth;
534
- }
535
-
536
- if let Some(fail_on_revert) = fail_on_revert {
537
- invariant.fail_on_revert = fail_on_revert;
538
- }
539
-
540
- if let Some(call_override) = call_override {
541
- invariant.call_override = call_override;
542
- }
543
-
544
- if let Some(dictionary_weight) = dictionary_weight {
545
- invariant.dictionary.dictionary_weight = dictionary_weight;
546
- }
547
-
548
- if let Some(include_storage) = include_storage {
549
- invariant.dictionary.include_storage = include_storage;
550
- }
551
-
552
- if let Some(include_push_bytes) = include_push_bytes {
553
- invariant.dictionary.include_push_bytes = include_push_bytes;
554
- }
555
-
556
- if let Some(shrink_run_limit) = shrink_run_limit {
557
- invariant.shrink_run_limit = shrink_run_limit;
558
- }
559
-
560
- invariant
561
- }
562
- }
563
-
564
- /// Settings to configure caching of remote RPC endpoints.
565
- #[napi(object)]
566
- #[derive(Clone, Debug, serde::Serialize)]
567
- pub struct StorageCachingConfig {
568
- /// Chains to cache. Either all or none or a list of chain names, e.g.
569
- /// ["optimism", "mainnet"].
570
- pub chains: Either<CachedChains, Vec<String>>,
571
- /// Endpoints to cache. Either all or remote or a regex.
572
- pub endpoints: Either<CachedEndpoints, String>,
573
- }
574
-
575
- impl Default for StorageCachingConfig {
576
- fn default() -> Self {
577
- Self {
578
- chains: Either::A(CachedChains::default()),
579
- endpoints: Either::A(CachedEndpoints::default()),
580
- }
581
- }
582
- }
583
-
584
- impl TryFrom<StorageCachingConfig> for foundry_cheatcodes::StorageCachingConfig {
585
- type Error = napi::Error;
586
-
587
- fn try_from(value: StorageCachingConfig) -> Result<Self, Self::Error> {
588
- let chains = match value.chains {
589
- Either::A(chains) => chains.into(),
590
- Either::B(chains) => {
591
- let chains = chains
592
- .into_iter()
593
- .map(|c| {
594
- c.parse()
595
- .map_err(|c| napi::Error::new(Status::InvalidArg, c))
596
- })
597
- .collect::<Result<_, _>>()?;
598
- foundry_cheatcodes::CachedChains::Chains(chains)
599
- }
600
- };
601
- let endpoints = match value.endpoints {
602
- Either::A(endpoints) => endpoints.into(),
603
- Either::B(regex) => {
604
- let regex = regex.parse().map_err(|_err| {
605
- napi::Error::new(Status::InvalidArg, format!("Invalid regex: {regex}"))
606
- })?;
607
- foundry_cheatcodes::CachedEndpoints::Pattern(regex)
608
- }
609
- };
610
- Ok(Self { chains, endpoints })
611
- }
612
- }
613
-
614
- /// What chains to cache
615
- #[napi]
616
- #[derive(Debug, Default, serde::Serialize)]
617
- pub enum CachedChains {
618
- /// Cache all chains
619
- #[default]
620
- All,
621
- /// Don't cache anything
622
- None,
623
- }
624
-
625
- impl From<CachedChains> for foundry_cheatcodes::CachedChains {
626
- fn from(value: CachedChains) -> Self {
627
- match value {
628
- CachedChains::All => foundry_cheatcodes::CachedChains::All,
629
- CachedChains::None => foundry_cheatcodes::CachedChains::None,
630
- }
631
- }
632
- }
633
-
634
- /// What endpoints to enable caching for
635
- #[napi]
636
- #[derive(Debug, Default, serde::Serialize)]
637
- pub enum CachedEndpoints {
638
- /// Cache all endpoints
639
- #[default]
640
- All,
641
- /// Only cache non-local host endpoints
642
- Remote,
643
- }
644
-
645
- impl From<CachedEndpoints> for foundry_cheatcodes::CachedEndpoints {
646
- fn from(value: CachedEndpoints) -> Self {
647
- match value {
648
- CachedEndpoints::All => foundry_cheatcodes::CachedEndpoints::All,
649
- CachedEndpoints::Remote => foundry_cheatcodes::CachedEndpoints::Remote,
650
- }
651
- }
652
- }
653
-
654
- /// Represents an access permission to a single path
655
- #[napi(object)]
656
- #[derive(Clone, Debug, serde::Serialize)]
657
- pub struct PathPermission {
658
- /// Permission level to access the `path`
659
- pub access: FsAccessPermission,
660
- /// The targeted path guarded by the permission
661
- pub path: String,
662
- }
663
-
664
- impl From<PathPermission> for foundry_cheatcodes::PathPermission {
665
- fn from(value: PathPermission) -> Self {
666
- let PathPermission { access, path } = value;
667
- Self {
668
- access: access.into(),
669
- path: path.into(),
670
- }
671
- }
672
- }
673
-
674
- /**
675
- * Determines the level of file system access for the given path.
676
- *
677
- * Exact path matching is used for file permissions. Prefix matching is used
678
- * for directory permissions.
679
- *
680
- * Giving write access to configuration files, source files or executables
681
- * in a project is considered dangerous, because it can be used by malicious
682
- * Solidity dependencies to escape the EVM sandbox. It is therefore
683
- * recommended to give write access to specific safe files only. If write
684
- * access to a directory is needed, please make sure that it doesn't contain
685
- * configuration files, source files or executables neither in the top level
686
- * directory, nor in any subdirectories.
687
- */
688
- #[napi]
689
- #[derive(Debug, serde::Serialize)]
690
- pub enum FsAccessPermission {
691
- /// Allows reading and writing the file
692
- ReadWriteFile,
693
- /// Only allows reading the file
694
- ReadFile,
695
- /// Only allows writing the file
696
- WriteFile,
697
- /// Allows reading and writing all files in the directory and its
698
- /// subdirectories
699
- DangerouslyReadWriteDirectory,
700
- /// Allows reading all files in the directory and its subdirectories
701
- ReadDirectory,
702
- /// Allows writing all files in the directory and its subdirectories
703
- DangerouslyWriteDirectory,
704
- }
705
-
706
- impl From<FsAccessPermission> for foundry_cheatcodes::FsAccessPermission {
707
- fn from(value: FsAccessPermission) -> Self {
708
- match value {
709
- FsAccessPermission::ReadWriteFile => {
710
- foundry_cheatcodes::FsAccessPermission::ReadWriteFile
711
- }
712
- FsAccessPermission::ReadFile => foundry_cheatcodes::FsAccessPermission::ReadFile,
713
- FsAccessPermission::WriteFile => foundry_cheatcodes::FsAccessPermission::WriteFile,
714
- FsAccessPermission::DangerouslyReadWriteDirectory => {
715
- foundry_cheatcodes::FsAccessPermission::DangerouslyReadWriteDirectory
716
- }
717
- FsAccessPermission::ReadDirectory => {
718
- foundry_cheatcodes::FsAccessPermission::ReadDirectory
719
- }
720
- FsAccessPermission::DangerouslyWriteDirectory => {
721
- foundry_cheatcodes::FsAccessPermission::DangerouslyWriteDirectory
722
- }
723
- }
724
- }
725
- }
726
-
727
- #[napi(object)]
728
- #[derive(Clone, Debug, serde::Serialize)]
729
- pub struct AddressLabel {
730
- /// The address to label
731
- #[serde(serialize_with = "serialize_uint8array_as_hex")]
732
- #[debug("{}", hex::encode(address))]
733
- pub address: Uint8Array,
734
- /// The label to assign to the address
735
- pub label: String,
736
- }
737
-
738
- /// A type that controls when stack traces are collected.
739
- #[napi]
740
- #[derive(Debug, serde::Serialize)]
741
- pub enum CollectStackTraces {
742
- /// Always collects stack traces, adding performance overhead.
743
- Always,
744
- /// Only collects stack traces upon failure, re-executing the test. This
745
- /// minimizes performance overhead.
746
- ///
747
- /// Not all tests can be re-executed since certain cheatcodes contain
748
- /// non-deterministic side-effects.
749
- OnFailure,
750
- }
751
-
752
- impl From<CollectStackTraces> for edr_solidity_tests::CollectStackTraces {
753
- fn from(value: CollectStackTraces) -> Self {
754
- match value {
755
- CollectStackTraces::Always => edr_solidity_tests::CollectStackTraces::Always,
756
- CollectStackTraces::OnFailure => edr_solidity_tests::CollectStackTraces::OnFailure,
757
- }
758
- }
759
- }
760
-
761
- /// Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
762
- /// controls execution trace decoding and inclusion in test results.
763
- #[napi]
764
- #[derive(Debug, Default, PartialEq, Eq, serde::Serialize)]
765
- pub enum IncludeTraces {
766
- /// No traces will be included in any test result.
767
- #[default]
768
- None,
769
- /// Traces will be included only on the results of failed tests.
770
- Failing,
771
- /// Traces will be included in all test results.
772
- All,
773
- }
774
-
775
- impl From<IncludeTraces> for edr_solidity_tests::IncludeTraces {
776
- fn from(value: IncludeTraces) -> Self {
777
- match value {
778
- IncludeTraces::None => edr_solidity_tests::IncludeTraces::None,
779
- IncludeTraces::Failing => edr_solidity_tests::IncludeTraces::Failing,
780
- IncludeTraces::All => edr_solidity_tests::IncludeTraces::All,
781
- }
782
- }
783
- }
784
-
785
- impl From<edr_solidity_tests::IncludeTraces> for IncludeTraces {
786
- fn from(value: edr_solidity_tests::IncludeTraces) -> Self {
787
- match value {
788
- edr_solidity_tests::IncludeTraces::None => IncludeTraces::None,
789
- edr_solidity_tests::IncludeTraces::Failing => IncludeTraces::Failing,
790
- edr_solidity_tests::IncludeTraces::All => IncludeTraces::All,
791
- }
792
- }
793
- }