@nomicfoundation/edr 0.12.0-next.2 → 0.12.0-next.20

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/src/provider.rs CHANGED
@@ -5,18 +5,18 @@ mod response;
5
5
  use std::sync::Arc;
6
6
 
7
7
  use edr_napi_core::provider::SyncProvider;
8
- use edr_solidity::contract_decoder::ContractDecoder;
8
+ use edr_solidity::compiler::create_models_and_decode_bytecodes;
9
9
  use napi::{tokio::runtime, Env, JsFunction, JsObject, Status};
10
10
  use napi_derive::napi;
11
11
 
12
12
  pub use self::factory::ProviderFactory;
13
13
  use self::response::Response;
14
- use crate::call_override::CallOverrideCallback;
14
+ use crate::{call_override::CallOverrideCallback, contract_decoder::ContractDecoder};
15
15
 
16
16
  /// A JSON-RPC provider for Ethereum.
17
17
  #[napi]
18
18
  pub struct Provider {
19
- contract_decoder: Arc<ContractDecoder>,
19
+ contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>,
20
20
  provider: Arc<dyn SyncProvider>,
21
21
  runtime: runtime::Handle,
22
22
  #[cfg(feature = "scenarios")]
@@ -28,7 +28,7 @@ impl Provider {
28
28
  pub fn new(
29
29
  provider: Arc<dyn SyncProvider>,
30
30
  runtime: runtime::Handle,
31
- contract_decoder: Arc<ContractDecoder>,
31
+ contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>,
32
32
  #[cfg(feature = "scenarios")] scenario_file: Option<
33
33
  napi::tokio::sync::Mutex<napi::tokio::fs::File>,
34
34
  >,
@@ -45,6 +45,53 @@ impl Provider {
45
45
 
46
46
  #[napi]
47
47
  impl Provider {
48
+ #[doc = "Adds a compilation result to the instance."]
49
+ #[doc = ""]
50
+ #[doc = "For internal use only. Support for this method may be removed in the future."]
51
+ #[napi(catch_unwind)]
52
+ pub async fn add_compilation_result(
53
+ &self,
54
+ solc_version: String,
55
+ compiler_input: serde_json::Value,
56
+ compiler_output: serde_json::Value,
57
+ ) -> napi::Result<()> {
58
+ let contract_decoder = self.contract_decoder.clone();
59
+
60
+ self.runtime
61
+ .spawn_blocking(move || {
62
+ let compiler_input = serde_json::from_value(compiler_input)
63
+ .map_err(|error| napi::Error::from_reason(error.to_string()))?;
64
+
65
+ let compiler_output = serde_json::from_value(compiler_output)
66
+ .map_err(|error| napi::Error::from_reason(error.to_string()))?;
67
+
68
+ let contracts = match create_models_and_decode_bytecodes(
69
+ solc_version,
70
+ &compiler_input,
71
+ &compiler_output,
72
+ ) {
73
+ Ok(contracts) => contracts,
74
+ Err(error) => {
75
+ return Err(napi::Error::from_reason(format!("Contract decoder failed to be updated. Please report this to help us improve Hardhat.\n{error}")));
76
+ }
77
+ };
78
+
79
+ for contract in contracts {
80
+ contract_decoder.add_contract_metadata(contract);
81
+ }
82
+
83
+ Ok(())
84
+ })
85
+ .await
86
+ .map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))?
87
+ }
88
+
89
+ #[doc = "Retrieves the instance's contract decoder."]
90
+ #[napi(catch_unwind)]
91
+ pub fn contract_decoder(&self) -> ContractDecoder {
92
+ ContractDecoder::from(Arc::clone(&self.contract_decoder))
93
+ }
94
+
48
95
  #[doc = "Handles a JSON-RPC request and returns a JSON-RPC response."]
49
96
  #[napi(catch_unwind)]
50
97
  pub async fn handle_request(&self, request: String) -> napi::Result<Response> {
package/src/result.rs CHANGED
@@ -1,4 +1,5 @@
1
- use edr_evm::trace::AfterMessage;
1
+ use edr_chain_spec::EvmHaltReason;
2
+ use edr_tracing::AfterMessage;
2
3
  use napi::{
3
4
  bindgen_prelude::{BigInt, Either3, Uint8Array},
4
5
  Either,
@@ -16,27 +17,24 @@ pub enum SuccessReason {
16
17
  Return,
17
18
  /// The opcode `SELFDESTRUCT` was called
18
19
  SelfDestruct,
19
- EofReturnContract,
20
20
  }
21
21
 
22
- impl From<edr_eth::result::SuccessReason> for SuccessReason {
23
- fn from(eval: edr_eth::result::SuccessReason) -> Self {
22
+ impl From<edr_chain_spec_evm::result::SuccessReason> for SuccessReason {
23
+ fn from(eval: edr_chain_spec_evm::result::SuccessReason) -> Self {
24
24
  match eval {
25
- edr_eth::result::SuccessReason::Stop => Self::Stop,
26
- edr_eth::result::SuccessReason::Return => Self::Return,
27
- edr_eth::result::SuccessReason::SelfDestruct => Self::SelfDestruct,
28
- edr_eth::result::SuccessReason::EofReturnContract => Self::EofReturnContract,
25
+ edr_chain_spec_evm::result::SuccessReason::Stop => Self::Stop,
26
+ edr_chain_spec_evm::result::SuccessReason::Return => Self::Return,
27
+ edr_chain_spec_evm::result::SuccessReason::SelfDestruct => Self::SelfDestruct,
29
28
  }
30
29
  }
31
30
  }
32
31
 
33
- impl From<SuccessReason> for edr_eth::result::SuccessReason {
32
+ impl From<SuccessReason> for edr_chain_spec_evm::result::SuccessReason {
34
33
  fn from(value: SuccessReason) -> Self {
35
34
  match value {
36
35
  SuccessReason::Stop => Self::Stop,
37
36
  SuccessReason::Return => Self::Return,
38
37
  SuccessReason::SelfDestruct => Self::SelfDestruct,
39
- SuccessReason::EofReturnContract => Self::EofReturnContract,
40
38
  }
41
39
  }
42
40
  }
@@ -100,81 +98,40 @@ pub enum ExceptionalHalt {
100
98
  CreateContractStartingWithEF,
101
99
  /// EIP-3860: Limit and meter initcode. Initcode size limit exceeded.
102
100
  CreateInitCodeSizeLimit,
103
- /// Aux data overflow, new aux data is larger tha u16 max size.
104
- EofAuxDataOverflow,
105
- /// Aud data is smaller then already present data size.
106
- EofAuxDataTooSmall,
107
- /// EOF Subroutine stack overflow
108
- SubRoutineStackOverflow,
109
- /// Check for target address validity is only done inside subcall.
110
- InvalidEXTCALLTarget,
111
101
  }
112
102
 
113
- impl From<edr_eth::l1::HaltReason> for ExceptionalHalt {
114
- fn from(halt: edr_eth::l1::HaltReason) -> Self {
103
+ impl From<EvmHaltReason> for ExceptionalHalt {
104
+ fn from(halt: EvmHaltReason) -> Self {
115
105
  match halt {
116
- edr_eth::l1::HaltReason::OutOfGas(..) => ExceptionalHalt::OutOfGas,
117
- edr_eth::l1::HaltReason::OpcodeNotFound => ExceptionalHalt::OpcodeNotFound,
118
- edr_eth::l1::HaltReason::InvalidFEOpcode => ExceptionalHalt::InvalidFEOpcode,
119
- edr_eth::l1::HaltReason::InvalidJump => ExceptionalHalt::InvalidJump,
120
- edr_eth::l1::HaltReason::NotActivated => ExceptionalHalt::NotActivated,
121
- edr_eth::l1::HaltReason::StackUnderflow => ExceptionalHalt::StackUnderflow,
122
- edr_eth::l1::HaltReason::StackOverflow => ExceptionalHalt::StackOverflow,
123
- edr_eth::l1::HaltReason::OutOfOffset => ExceptionalHalt::OutOfOffset,
124
- edr_eth::l1::HaltReason::CreateCollision => ExceptionalHalt::CreateCollision,
125
- edr_eth::l1::HaltReason::PrecompileError => ExceptionalHalt::PrecompileError,
126
- edr_eth::l1::HaltReason::NonceOverflow => ExceptionalHalt::NonceOverflow,
127
- edr_eth::l1::HaltReason::CreateContractSizeLimit => {
128
- ExceptionalHalt::CreateContractSizeLimit
106
+ EvmHaltReason::OutOfGas(..) => ExceptionalHalt::OutOfGas,
107
+ EvmHaltReason::OpcodeNotFound => ExceptionalHalt::OpcodeNotFound,
108
+ EvmHaltReason::InvalidFEOpcode => ExceptionalHalt::InvalidFEOpcode,
109
+ EvmHaltReason::InvalidJump => ExceptionalHalt::InvalidJump,
110
+ EvmHaltReason::NotActivated => ExceptionalHalt::NotActivated,
111
+ EvmHaltReason::StackUnderflow => ExceptionalHalt::StackUnderflow,
112
+ EvmHaltReason::StackOverflow => ExceptionalHalt::StackOverflow,
113
+ EvmHaltReason::OutOfOffset => ExceptionalHalt::OutOfOffset,
114
+ EvmHaltReason::CreateCollision => ExceptionalHalt::CreateCollision,
115
+ EvmHaltReason::PrecompileError | EvmHaltReason::PrecompileErrorWithContext(_) => {
116
+ ExceptionalHalt::PrecompileError
129
117
  }
130
- edr_eth::l1::HaltReason::CreateContractStartingWithEF => {
118
+ EvmHaltReason::NonceOverflow => ExceptionalHalt::NonceOverflow,
119
+ EvmHaltReason::CreateContractSizeLimit => ExceptionalHalt::CreateContractSizeLimit,
120
+ EvmHaltReason::CreateContractStartingWithEF => {
131
121
  ExceptionalHalt::CreateContractStartingWithEF
132
122
  }
133
- edr_eth::l1::HaltReason::CreateInitCodeSizeLimit => {
134
- ExceptionalHalt::CreateInitCodeSizeLimit
135
- }
136
- edr_eth::l1::HaltReason::EofAuxDataOverflow => ExceptionalHalt::EofAuxDataOverflow,
137
- edr_eth::l1::HaltReason::EofAuxDataTooSmall => ExceptionalHalt::EofAuxDataTooSmall,
138
- edr_eth::l1::HaltReason::SubRoutineStackOverflow => {
139
- ExceptionalHalt::SubRoutineStackOverflow
140
- }
141
- edr_eth::l1::HaltReason::InvalidEXTCALLTarget => ExceptionalHalt::InvalidEXTCALLTarget,
142
- edr_eth::l1::HaltReason::OverflowPayment
143
- | edr_eth::l1::HaltReason::StateChangeDuringStaticCall
144
- | edr_eth::l1::HaltReason::CallNotAllowedInsideStatic
145
- | edr_eth::l1::HaltReason::OutOfFunds
146
- | edr_eth::l1::HaltReason::CallTooDeep => {
123
+ EvmHaltReason::CreateInitCodeSizeLimit => ExceptionalHalt::CreateInitCodeSizeLimit,
124
+ EvmHaltReason::OverflowPayment
125
+ | EvmHaltReason::StateChangeDuringStaticCall
126
+ | EvmHaltReason::CallNotAllowedInsideStatic
127
+ | EvmHaltReason::OutOfFunds
128
+ | EvmHaltReason::CallTooDeep => {
147
129
  unreachable!("Internal halts that can be only found inside Inspector: {halt:?}")
148
130
  }
149
131
  }
150
132
  }
151
133
  }
152
134
 
153
- impl From<ExceptionalHalt> for edr_eth::l1::HaltReason {
154
- fn from(value: ExceptionalHalt) -> Self {
155
- match value {
156
- ExceptionalHalt::OutOfGas => Self::OutOfGas(edr_eth::l1::OutOfGasError::Basic),
157
- ExceptionalHalt::OpcodeNotFound => Self::OpcodeNotFound,
158
- ExceptionalHalt::InvalidFEOpcode => Self::InvalidFEOpcode,
159
- ExceptionalHalt::InvalidJump => Self::InvalidJump,
160
- ExceptionalHalt::NotActivated => Self::NotActivated,
161
- ExceptionalHalt::StackUnderflow => Self::StackUnderflow,
162
- ExceptionalHalt::StackOverflow => Self::StackOverflow,
163
- ExceptionalHalt::OutOfOffset => Self::OutOfOffset,
164
- ExceptionalHalt::CreateCollision => Self::CreateCollision,
165
- ExceptionalHalt::PrecompileError => Self::PrecompileError,
166
- ExceptionalHalt::NonceOverflow => Self::NonceOverflow,
167
- ExceptionalHalt::CreateContractSizeLimit => Self::CreateContractSizeLimit,
168
- ExceptionalHalt::CreateContractStartingWithEF => Self::CreateContractStartingWithEF,
169
- ExceptionalHalt::CreateInitCodeSizeLimit => Self::CreateInitCodeSizeLimit,
170
- ExceptionalHalt::EofAuxDataOverflow => Self::EofAuxDataOverflow,
171
- ExceptionalHalt::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
172
- ExceptionalHalt::SubRoutineStackOverflow => Self::SubRoutineStackOverflow,
173
- ExceptionalHalt::InvalidEXTCALLTarget => Self::InvalidEXTCALLTarget,
174
- }
175
- }
176
- }
177
-
178
135
  /// The result when the EVM terminates due to an exceptional halt.
179
136
  #[napi(object)]
180
137
  pub struct HaltResult {
@@ -194,15 +151,15 @@ pub struct ExecutionResult {
194
151
  pub contract_address: Option<Uint8Array>,
195
152
  }
196
153
 
197
- impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
198
- fn from(value: &AfterMessage<edr_eth::l1::HaltReason>) -> Self {
154
+ impl From<&AfterMessage<EvmHaltReason>> for ExecutionResult {
155
+ fn from(value: &AfterMessage<EvmHaltReason>) -> Self {
199
156
  let AfterMessage {
200
157
  execution_result,
201
158
  contract_address,
202
159
  } = value;
203
160
 
204
161
  let result = match execution_result {
205
- edr_eth::result::ExecutionResult::Success {
162
+ edr_chain_spec_evm::result::ExecutionResult::Success {
206
163
  reason,
207
164
  gas_used,
208
165
  gas_refunded,
@@ -217,12 +174,12 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
217
174
  gas_refunded: BigInt::from(*gas_refunded),
218
175
  logs,
219
176
  output: match output {
220
- edr_eth::result::Output::Call(return_value) => {
177
+ edr_chain_spec_evm::result::Output::Call(return_value) => {
221
178
  let return_value = Uint8Array::with_data_copied(return_value);
222
179
 
223
180
  Either::A(CallOutput { return_value })
224
181
  }
225
- edr_eth::result::Output::Create(return_value, address) => {
182
+ edr_chain_spec_evm::result::Output::Create(return_value, address) => {
226
183
  let return_value = Uint8Array::with_data_copied(return_value);
227
184
 
228
185
  Either::B(CreateOutput {
@@ -233,7 +190,7 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
233
190
  },
234
191
  })
235
192
  }
236
- edr_eth::result::ExecutionResult::Revert { gas_used, output } => {
193
+ edr_chain_spec_evm::result::ExecutionResult::Revert { gas_used, output } => {
237
194
  let output = Uint8Array::with_data_copied(output);
238
195
 
239
196
  Either3::B(RevertResult {
@@ -241,10 +198,12 @@ impl From<&AfterMessage<edr_eth::l1::HaltReason>> for ExecutionResult {
241
198
  output,
242
199
  })
243
200
  }
244
- edr_eth::result::ExecutionResult::Halt { reason, gas_used } => Either3::C(HaltResult {
245
- reason: ExceptionalHalt::from(*reason),
246
- gas_used: BigInt::from(*gas_used),
247
- }),
201
+ edr_chain_spec_evm::result::ExecutionResult::Halt { reason, gas_used } => {
202
+ Either3::C(HaltResult {
203
+ reason: ExceptionalHalt::from(reason.clone()),
204
+ gas_used: BigInt::from(*gas_used),
205
+ })
206
+ }
248
207
  };
249
208
 
250
209
  let contract_address = contract_address.as_ref().map(Uint8Array::with_data_copied);
package/src/serde.rs CHANGED
@@ -1,4 +1,4 @@
1
- use edr_eth::hex;
1
+ use edr_primitives::hex;
2
2
  use napi::bindgen_prelude::{BigInt, Uint8Array};
3
3
  use serde::Serializer;
4
4
 
@@ -1,14 +1,14 @@
1
1
  use std::{collections::HashMap, path::PathBuf};
2
2
 
3
3
  use derive_more::Debug;
4
- use edr_eth::hex;
4
+ use edr_primitives::hex;
5
5
  use edr_solidity_tests::{
6
6
  executors::invariant::InvariantConfig,
7
7
  fuzz::FuzzConfig,
8
8
  inspectors::cheatcodes::{CheatsConfigOptions, ExecutionContextConfig},
9
9
  TestFilterConfig,
10
10
  };
11
- use foundry_cheatcodes::{FsPermissions, RpcEndpoint, RpcEndpoints};
11
+ use foundry_cheatcodes::{FsPermissions, RpcEndpointUrl, RpcEndpoints};
12
12
  use napi::{
13
13
  bindgen_prelude::{BigInt, Uint8Array},
14
14
  tokio::runtime,
@@ -36,8 +36,6 @@ pub struct SolidityTestRunnerConfigArgs {
36
36
  pub project_root: String,
37
37
  /// Configures the permissions of cheat codes that access the file system.
38
38
  pub fs_permissions: Option<Vec<PathPermission>>,
39
- /// Whether to support the `testFail` prefix. Defaults to false.
40
- pub test_fail: Option<bool>,
41
39
  /// Address labels for traces. Defaults to none.
42
40
  pub labels: Option<Vec<AddressLabel>>,
43
41
  /// Whether to enable isolation of calls. In isolation mode all top-level
@@ -109,7 +107,7 @@ pub struct SolidityTestRunnerConfigArgs {
109
107
  /// Defaults to false.
110
108
  pub disable_block_gas_limit: Option<bool>,
111
109
  /// The memory limit of the EVM in bytes.
112
- /// Defaults to 33_554_432 (2^25 = 32MiB).
110
+ /// Defaults to `33_554_432` (2^25 = 32MiB).
113
111
  #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
114
112
  pub memory_limit: Option<BigInt>,
115
113
  /// The predeploys applied in local mode. Defaults to no predeploys.
@@ -143,6 +141,8 @@ pub struct SolidityTestRunnerConfigArgs {
143
141
  /// If an invariant config setting is not set, but a corresponding fuzz
144
142
  /// config value is set, then the fuzz config value will be used.
145
143
  pub invariant: Option<InvariantConfigArgs>,
144
+ /// Whether to collect stack traces.
145
+ pub collect_stack_traces: Option<CollectStackTraces>,
146
146
  /// Controls which test results should include execution traces. Defaults to
147
147
  /// None.
148
148
  pub include_traces: Option<IncludeTraces>,
@@ -153,6 +153,11 @@ pub struct SolidityTestRunnerConfigArgs {
153
153
  /// A regex pattern to filter tests. If provided, only test methods that
154
154
  /// match the pattern will be executed and reported as a test result.
155
155
  pub test_pattern: Option<String>,
156
+ /// Controls whether to generate a gas report after running the tests.
157
+ /// Enabling this also enables collection of all traces and EVM isolation
158
+ /// mode.
159
+ /// Defaults to false.
160
+ pub generate_gas_report: Option<bool>,
156
161
  }
157
162
 
158
163
  impl SolidityTestRunnerConfigArgs {
@@ -166,7 +171,6 @@ impl SolidityTestRunnerConfigArgs {
166
171
  let SolidityTestRunnerConfigArgs {
167
172
  project_root,
168
173
  fs_permissions,
169
- test_fail,
170
174
  labels,
171
175
  isolate,
172
176
  ffi,
@@ -194,9 +198,11 @@ impl SolidityTestRunnerConfigArgs {
194
198
  prompt_timeout,
195
199
  fuzz,
196
200
  invariant,
201
+ collect_stack_traces,
197
202
  include_traces,
198
203
  observability,
199
204
  test_pattern,
205
+ generate_gas_report,
200
206
  } = self;
201
207
 
202
208
  let test_pattern = TestFilterConfig {
@@ -237,7 +243,7 @@ impl SolidityTestRunnerConfigArgs {
237
243
  RpcEndpoints::new(
238
244
  endpoints
239
245
  .into_iter()
240
- .map(|(chain, url)| (chain, RpcEndpoint::Url(url))),
246
+ .map(|(chain, url)| (chain, RpcEndpointUrl::new(url))),
241
247
  )
242
248
  })
243
249
  .unwrap_or_default(),
@@ -258,6 +264,7 @@ impl SolidityTestRunnerConfigArgs {
258
264
  .into_iter()
259
265
  .map(|AddressLabel { address, label }| Ok((address.try_cast()?, label)))
260
266
  .collect::<Result<_, napi::Error>>()?,
267
+ seed: fuzz.seed,
261
268
  allow_internal_expect_revert: allow_internal_expect_revert.unwrap_or(false),
262
269
  };
263
270
 
@@ -273,7 +280,6 @@ impl SolidityTestRunnerConfigArgs {
273
280
  let config = edr_napi_core::solidity::config::TestRunnerConfig {
274
281
  project_root: project_root.into(),
275
282
  include_traces: include_traces.unwrap_or_default().into(),
276
- test_fail: test_fail.unwrap_or_default(),
277
283
  isolate,
278
284
  ffi,
279
285
  sender: sender.map(TryCast::try_cast).transpose()?,
@@ -296,8 +302,13 @@ impl SolidityTestRunnerConfigArgs {
296
302
  cheatcode,
297
303
  fuzz,
298
304
  invariant,
305
+ collect_stack_traces: collect_stack_traces.map_or(
306
+ edr_solidity_tests::CollectStackTraces::OnFailure,
307
+ edr_solidity_tests::CollectStackTraces::from,
308
+ ),
299
309
  on_collected_coverage_fn,
300
310
  test_pattern,
311
+ generate_gas_report,
301
312
  };
302
313
 
303
314
  Ok(config)
@@ -356,7 +367,7 @@ impl TryFrom<FuzzConfigArgs> for FuzzConfig {
356
367
  } = value;
357
368
 
358
369
  let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
359
- let failure_persist_file = failure_persist_file.unwrap_or("failures".to_string());
370
+ let failure_persist_file = failure_persist_file.unwrap_or_else(|| "failures".to_string());
360
371
  let seed = seed
361
372
  .map(|s| {
362
373
  s.parse().map_err(|_err| {
@@ -447,6 +458,10 @@ pub struct InvariantConfigArgs {
447
458
  /// process is disabled if set to 0.
448
459
  /// Defaults to 5000.
449
460
  pub shrink_run_limit: Option<u32>,
461
+ /// The maximum number of rejects via `vm.assume` which can be encountered
462
+ /// during a single invariant run.
463
+ /// Defaults to 65536.
464
+ pub max_assume_rejects: Option<u32>,
450
465
  }
451
466
 
452
467
  impl InvariantConfigArgs {
@@ -500,6 +515,7 @@ impl From<InvariantConfigArgs> for InvariantConfig {
500
515
  include_storage,
501
516
  include_push_bytes,
502
517
  shrink_run_limit,
518
+ max_assume_rejects,
503
519
  } = value;
504
520
 
505
521
  let failure_persist_dir = failure_persist_dir.map(PathBuf::from);
@@ -543,6 +559,10 @@ impl From<InvariantConfigArgs> for InvariantConfig {
543
559
  invariant.shrink_run_limit = shrink_run_limit;
544
560
  }
545
561
 
562
+ if let Some(max_assume_rejects) = max_assume_rejects {
563
+ invariant.max_assume_rejects = max_assume_rejects;
564
+ }
565
+
546
566
  invariant
547
567
  }
548
568
  }
@@ -657,24 +677,55 @@ impl From<PathPermission> for foundry_cheatcodes::PathPermission {
657
677
  }
658
678
  }
659
679
 
660
- /// Determines the status of file system access
680
+ /**
681
+ * Determines the level of file system access for the given path.
682
+ *
683
+ * Exact path matching is used for file permissions. Prefix matching is used
684
+ * for directory permissions.
685
+ *
686
+ * Giving write access to configuration files, source files or executables
687
+ * in a project is considered dangerous, because it can be used by malicious
688
+ * Solidity dependencies to escape the EVM sandbox. It is therefore
689
+ * recommended to give write access to specific safe files only. If write
690
+ * access to a directory is needed, please make sure that it doesn't contain
691
+ * configuration files, source files or executables neither in the top level
692
+ * directory, nor in any subdirectories.
693
+ */
661
694
  #[napi]
662
695
  #[derive(Debug, serde::Serialize)]
663
696
  pub enum FsAccessPermission {
664
- /// FS access is allowed with `read` + `write` permission
665
- ReadWrite,
666
- /// Only reading is allowed
667
- Read,
668
- /// Only writing is allowed
669
- Write,
697
+ /// Allows reading and writing the file
698
+ ReadWriteFile,
699
+ /// Only allows reading the file
700
+ ReadFile,
701
+ /// Only allows writing the file
702
+ WriteFile,
703
+ /// Allows reading and writing all files in the directory and its
704
+ /// subdirectories
705
+ DangerouslyReadWriteDirectory,
706
+ /// Allows reading all files in the directory and its subdirectories
707
+ ReadDirectory,
708
+ /// Allows writing all files in the directory and its subdirectories
709
+ DangerouslyWriteDirectory,
670
710
  }
671
711
 
672
712
  impl From<FsAccessPermission> for foundry_cheatcodes::FsAccessPermission {
673
713
  fn from(value: FsAccessPermission) -> Self {
674
714
  match value {
675
- FsAccessPermission::ReadWrite => foundry_cheatcodes::FsAccessPermission::ReadWrite,
676
- FsAccessPermission::Read => foundry_cheatcodes::FsAccessPermission::Read,
677
- FsAccessPermission::Write => foundry_cheatcodes::FsAccessPermission::Write,
715
+ FsAccessPermission::ReadWriteFile => {
716
+ foundry_cheatcodes::FsAccessPermission::ReadWriteFile
717
+ }
718
+ FsAccessPermission::ReadFile => foundry_cheatcodes::FsAccessPermission::ReadFile,
719
+ FsAccessPermission::WriteFile => foundry_cheatcodes::FsAccessPermission::WriteFile,
720
+ FsAccessPermission::DangerouslyReadWriteDirectory => {
721
+ foundry_cheatcodes::FsAccessPermission::DangerouslyReadWriteDirectory
722
+ }
723
+ FsAccessPermission::ReadDirectory => {
724
+ foundry_cheatcodes::FsAccessPermission::ReadDirectory
725
+ }
726
+ FsAccessPermission::DangerouslyWriteDirectory => {
727
+ foundry_cheatcodes::FsAccessPermission::DangerouslyWriteDirectory
728
+ }
678
729
  }
679
730
  }
680
731
  }
@@ -690,6 +741,29 @@ pub struct AddressLabel {
690
741
  pub label: String,
691
742
  }
692
743
 
744
+ /// A type that controls when stack traces are collected.
745
+ #[napi]
746
+ #[derive(Debug, serde::Serialize)]
747
+ pub enum CollectStackTraces {
748
+ /// Always collects stack traces, adding performance overhead.
749
+ Always,
750
+ /// Only collects stack traces upon failure, re-executing the test. This
751
+ /// minimizes performance overhead.
752
+ ///
753
+ /// Not all tests can be re-executed since certain cheatcodes contain
754
+ /// non-deterministic side-effects.
755
+ OnFailure,
756
+ }
757
+
758
+ impl From<CollectStackTraces> for edr_solidity_tests::CollectStackTraces {
759
+ fn from(value: CollectStackTraces) -> Self {
760
+ match value {
761
+ CollectStackTraces::Always => edr_solidity_tests::CollectStackTraces::Always,
762
+ CollectStackTraces::OnFailure => edr_solidity_tests::CollectStackTraces::OnFailure,
763
+ }
764
+ }
765
+ }
766
+
693
767
  /// Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
694
768
  /// controls execution trace decoding and inclusion in test results.
695
769
  #[napi]
@@ -1,14 +1,18 @@
1
1
  use std::{collections::BTreeMap, sync::Arc};
2
2
 
3
- use edr_eth::Bytes;
4
3
  use edr_napi_core::solidity::{
5
4
  config::{TestRunnerConfig, TracingConfigWithBuffers},
6
5
  SyncTestRunner, SyncTestRunnerFactory,
7
6
  };
7
+ use edr_primitives::Bytes;
8
8
  use edr_solidity::artifacts::ArtifactId;
9
9
  use edr_solidity_tests::{
10
- contracts::ContractsByArtifact, decode::RevertDecoder, evm_context::L1EvmBuilder,
11
- multi_runner::TestContract, revm::context::TxEnv, MultiContractRunner,
10
+ contracts::ContractsByArtifact,
11
+ decode::RevertDecoder,
12
+ evm_context::L1EvmBuilder,
13
+ multi_runner::TestContract,
14
+ revm::context::{BlockEnv, TxEnv},
15
+ MultiContractRunner,
12
16
  };
13
17
  use napi::tokio;
14
18
  use napi_derive::napi;
@@ -33,13 +37,13 @@ impl SyncTestRunnerFactory for L1TestRunnerFactory {
33
37
  let runner = tokio::task::block_in_place(|| {
34
38
  runtime
35
39
  .block_on(MultiContractRunner::<
36
- edr_eth::l1::BlockEnv,
40
+ BlockEnv,
37
41
  (),
38
42
  L1EvmBuilder,
39
- edr_eth::l1::HaltReason,
40
- edr_eth::l1::SpecId,
43
+ edr_chain_l1::HaltReason,
44
+ edr_chain_l1::Hardfork,
41
45
  _,
42
- edr_eth::l1::InvalidTransaction,
46
+ edr_chain_l1::InvalidTransaction,
43
47
  TxEnv,
44
48
  >::new(
45
49
  config.try_into()?,
@@ -1,14 +1,17 @@
1
1
  use std::{collections::BTreeMap, sync::Arc};
2
2
 
3
- use edr_eth::Bytes;
4
3
  use edr_napi_core::solidity::{
5
4
  config::{TestRunnerConfig, TracingConfigWithBuffers},
6
5
  SyncTestRunner, SyncTestRunnerFactory,
7
6
  };
8
- use edr_op::solidity_tests::OpEvmBuilder;
7
+ use edr_op::{solidity_tests::OpEvmBuilder, transaction::OpTxEnv};
8
+ use edr_primitives::Bytes;
9
9
  use edr_solidity::artifacts::ArtifactId;
10
10
  use edr_solidity_tests::{
11
- contracts::ContractsByArtifact, decode::RevertDecoder, multi_runner::TestContract,
11
+ contracts::ContractsByArtifact,
12
+ decode::RevertDecoder,
13
+ multi_runner::TestContract,
14
+ revm::context::{BlockEnv, TxEnv},
12
15
  MultiContractRunner,
13
16
  };
14
17
  use napi::tokio;
@@ -34,14 +37,14 @@ impl SyncTestRunnerFactory for OpTestRunnerFactory {
34
37
  let runner = tokio::task::block_in_place(|| {
35
38
  runtime
36
39
  .block_on(MultiContractRunner::<
37
- edr_eth::l1::BlockEnv,
40
+ BlockEnv,
38
41
  _,
39
42
  OpEvmBuilder,
40
- edr_op::OpHaltReason,
41
- edr_op::OpSpecId,
43
+ edr_op::HaltReason,
44
+ edr_op::Hardfork,
42
45
  _,
43
- edr_op::transaction::InvalidTransaction,
44
- edr_op::transaction::OpTxEnv<edr_eth::l1::TxEnv>,
46
+ edr_op::InvalidTransaction,
47
+ OpTxEnv<TxEnv>,
45
48
  >::new(
46
49
  config.try_into()?,
47
50
  contracts,
@@ -1,6 +1,6 @@
1
1
  use std::sync::{Mutex, OnceLock};
2
2
 
3
- use edr_eth::spec::HaltReasonTrait;
3
+ use edr_chain_spec::HaltReasonTrait;
4
4
  use edr_napi_core::solidity::config::TracingConfigWithBuffers;
5
5
  use edr_solidity::{
6
6
  artifacts::BuildInfoConfigWithBuffers,