@nomicfoundation/edr 0.12.0-next.1 → 0.12.0-next.10

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/config.rs CHANGED
@@ -6,10 +6,10 @@ use std::{
6
6
  };
7
7
 
8
8
  use edr_coverage::reporter::SyncOnCollectedCoverageCallback;
9
- use edr_eth::{
10
- signature::{secret_key_from_str, SecretKey},
11
- Bytes, HashMap, HashSet,
12
- };
9
+ use edr_eip1559::{BaseFeeActivation, ConstantBaseFeeParams};
10
+ use edr_gas_report::SyncOnCollectedGasReportCallback;
11
+ use edr_primitives::{Bytes, HashMap, HashSet};
12
+ use edr_signer::{secret_key_from_str, SecretKey};
13
13
  use napi::{
14
14
  bindgen_prelude::{BigInt, Promise, Reference, Uint8Array},
15
15
  threadsafe_function::{
@@ -20,7 +20,53 @@ use napi::{
20
20
  };
21
21
  use napi_derive::napi;
22
22
 
23
- use crate::{account::AccountOverride, block::BlobGas, cast::TryCast, precompile::Precompile};
23
+ use crate::{
24
+ account::AccountOverride, block::BlobGas, cast::TryCast, gas_report::GasReport,
25
+ logger::LoggerConfig, precompile::Precompile, subscription::SubscriptionConfig,
26
+ };
27
+
28
+ /// Configuration for EIP-1559 parameters
29
+ #[napi(object)]
30
+ pub struct BaseFeeParamActivation {
31
+ pub activation: Either<BaseFeeActivationByBlockNumber, BaseFeeActivationByHardfork>,
32
+ pub max_change_denominator: BigInt,
33
+ pub elasticity_multiplier: BigInt,
34
+ }
35
+
36
+ #[napi(object)]
37
+ pub struct BaseFeeActivationByBlockNumber {
38
+ /// The block number at which the `base_fee_params` is activated
39
+ pub block_number: BigInt,
40
+ }
41
+ #[napi(object)]
42
+ pub struct BaseFeeActivationByHardfork {
43
+ /// The hardfork at which the `base_fee_params` is activated
44
+ pub hardfork: String,
45
+ }
46
+
47
+ impl TryFrom<BaseFeeParamActivation> for (BaseFeeActivation<String>, ConstantBaseFeeParams) {
48
+ type Error = napi::Error;
49
+
50
+ fn try_from(value: BaseFeeParamActivation) -> Result<Self, Self::Error> {
51
+ let base_fee_params = ConstantBaseFeeParams {
52
+ max_change_denominator: value.max_change_denominator.try_cast()?,
53
+ elasticity_multiplier: value.elasticity_multiplier.try_cast()?,
54
+ };
55
+
56
+ match value.activation {
57
+ Either::A(BaseFeeActivationByBlockNumber { block_number }) => {
58
+ let activation_block_number: u64 = block_number.try_cast()?;
59
+ Ok((
60
+ BaseFeeActivation::BlockNumber(activation_block_number),
61
+ base_fee_params,
62
+ ))
63
+ }
64
+ Either::B(BaseFeeActivationByHardfork { hardfork }) => {
65
+ Ok((BaseFeeActivation::Hardfork(hardfork), base_fee_params))
66
+ }
67
+ }
68
+ }
69
+ }
24
70
 
25
71
  /// Specification of a chain with possible overrides.
26
72
  #[napi(object)]
@@ -47,6 +93,17 @@ pub struct CodeCoverageConfig {
47
93
  pub on_collected_coverage_callback: JsFunction,
48
94
  }
49
95
 
96
+ #[napi(object)]
97
+ pub struct GasReportConfig {
98
+ /// Gas reports are collected after a block is mined or `eth_call` is
99
+ /// executed.
100
+ ///
101
+ /// Exceptions thrown in the callback will be propagated to the original
102
+ /// caller.
103
+ #[napi(ts_type = "(gasReport: GasReport) => Promise<void>")]
104
+ pub on_collected_gas_report_callback: JsFunction,
105
+ }
106
+
50
107
  /// Configuration for forking a blockchain
51
108
  #[napi(object)]
52
109
  pub struct ForkConfig {
@@ -124,6 +181,8 @@ pub struct MiningConfig {
124
181
  pub struct ObservabilityConfig {
125
182
  /// If present, configures runtime observability to collect code coverage.
126
183
  pub code_coverage: Option<CodeCoverageConfig>,
184
+ /// If present, configures runtime observability to collect gas reports.
185
+ pub gas_report: Option<GasReportConfig>,
127
186
  }
128
187
 
129
188
  /// Configuration for a provider
@@ -137,6 +196,15 @@ pub struct ProviderConfig {
137
196
  pub bail_on_call_failure: bool,
138
197
  /// Whether to return an `Err` when a `eth_sendTransaction` fails
139
198
  pub bail_on_transaction_failure: bool,
199
+ /// EIP-1559 base fee parameters activations to be used to calculate the
200
+ /// block base fee.
201
+ ///
202
+ /// Provide an ordered list of `base_fee_params` to be
203
+ /// used starting from the specified activation point (hardfork or block
204
+ /// number).
205
+ /// If not provided, the default values from the chain spec
206
+ /// will be used.
207
+ pub base_fee_config: Option<Vec<BaseFeeParamActivation>>,
140
208
  /// The gas limit of each block
141
209
  pub block_gas_limit: BigInt,
142
210
  /// The chain ID of the blockchain
@@ -331,6 +399,8 @@ impl ObservabilityConfig {
331
399
  .code_coverage
332
400
  .map(
333
401
  |code_coverage| -> napi::Result<Box<dyn SyncOnCollectedCoverageCallback>> {
402
+ let runtime = runtime.clone();
403
+
334
404
  let mut on_collected_coverage_callback: ThreadsafeFunction<
335
405
  _,
336
406
  ErrorStrategy::Fatal,
@@ -385,10 +455,10 @@ impl ObservabilityConfig {
385
455
  Ok(())
386
456
  });
387
457
 
388
- let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
389
-
390
458
  assert_eq!(status, napi::Status::Ok);
391
459
 
460
+ let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
461
+
392
462
  Ok(())
393
463
  });
394
464
 
@@ -396,9 +466,61 @@ impl ObservabilityConfig {
396
466
  },
397
467
  )
398
468
  .transpose()?;
469
+ let on_collected_gas_report_fn = self.gas_report.map(
470
+ |gas_report| -> napi::Result<Box<dyn SyncOnCollectedGasReportCallback>> {
471
+ let mut on_collected_gas_report_callback: ThreadsafeFunction<
472
+ _,
473
+ ErrorStrategy::Fatal,
474
+ > = gas_report
475
+ .on_collected_gas_report_callback
476
+ .create_threadsafe_function(
477
+ 0,
478
+ |ctx: ThreadSafeCallContext<GasReport>| {
479
+ let report = ctx.value;
480
+ Ok(vec![report])
481
+ }
482
+ ,
483
+ )?;
484
+ // Maintain a weak reference to the function to avoid blocking the event loop
485
+ // from exiting.
486
+ on_collected_gas_report_callback.unref(env)?;
487
+
488
+ let on_collected_gas_report_fn: Box<dyn SyncOnCollectedGasReportCallback> =
489
+ Box::new(move |report| {
490
+ let runtime = runtime.clone();
491
+
492
+ let (sender, receiver) = std::sync::mpsc::channel();
493
+
494
+ // Convert the report to the N-API representation
495
+ let status = on_collected_gas_report_callback
496
+ .call_with_return_value(GasReport::from(report), ThreadsafeFunctionCallMode::Blocking, move |result: Promise<()>| {
497
+ // We spawn a background task to handle the async callback
498
+ runtime.spawn(async move {
499
+ let result = result.await;
500
+ sender.send(result).map_err(|_error| {
501
+ napi::Error::new(
502
+ napi::Status::GenericFailure,
503
+ "Failed to send result from on_collected_gas_report_callback",
504
+ )
505
+ })
506
+ });
507
+ Ok(())
508
+ });
509
+
510
+ assert_eq!(status, napi::Status::Ok);
511
+
512
+ let () = receiver.recv().expect("Receive can only fail if the channel is closed")?;
513
+
514
+ Ok(())
515
+ });
516
+
517
+ Ok(on_collected_gas_report_fn)
518
+ },
519
+ ).transpose()?;
399
520
 
400
521
  Ok(edr_provider::observability::Config {
401
522
  on_collected_coverage_fn,
523
+ on_collected_gas_report_fn,
402
524
  ..edr_provider::observability::Config::default()
403
525
  })
404
526
  }
@@ -418,7 +540,7 @@ impl ProviderConfig {
418
540
  // This is the only place in production code where it's allowed to use
419
541
  // `DangerousSecretKeyStr`.
420
542
  #[allow(deprecated)]
421
- use edr_eth::signature::DangerousSecretKeyStr;
543
+ use edr_signer::DangerousSecretKeyStr;
422
544
 
423
545
  static_assertions::assert_not_impl_all!(JsString: Debug, Display, serde::Serialize);
424
546
  static_assertions::assert_not_impl_all!(JsStringUtf8: Debug, Display, serde::Serialize);
@@ -438,6 +560,11 @@ impl ProviderConfig {
438
560
  })
439
561
  .collect::<napi::Result<Vec<_>>>()?;
440
562
 
563
+ let base_fee_params: Option<Vec<(BaseFeeActivation<String>, ConstantBaseFeeParams)>> = self
564
+ .base_fee_config
565
+ .map(|vec| vec.into_iter().map(TryInto::try_into).collect())
566
+ .transpose()?;
567
+
441
568
  let block_gas_limit =
442
569
  NonZeroU64::new(self.block_gas_limit.try_cast()?).ok_or_else(|| {
443
570
  napi::Error::new(
@@ -450,7 +577,7 @@ impl ProviderConfig {
450
577
  .genesis_state
451
578
  .into_iter()
452
579
  .map(TryInto::try_into)
453
- .collect::<napi::Result<HashMap<edr_eth::Address, edr_provider::AccountOverride>>>()?;
580
+ .collect::<napi::Result<HashMap<edr_primitives::Address, edr_provider::AccountOverride>>>()?;
454
581
 
455
582
  let precompile_overrides = self
456
583
  .precompile_overrides
@@ -463,6 +590,7 @@ impl ProviderConfig {
463
590
  allow_unlimited_contract_size: self.allow_unlimited_contract_size,
464
591
  bail_on_call_failure: self.bail_on_call_failure,
465
592
  bail_on_transaction_failure: self.bail_on_transaction_failure,
593
+ base_fee_params,
466
594
  block_gas_limit,
467
595
  chain_id: self.chain_id.try_cast()?,
468
596
  coinbase: self.coinbase.try_cast()?,
@@ -541,3 +669,32 @@ impl From<BuildInfoAndOutput> for edr_napi_core::solidity::config::BuildInfoAndO
541
669
  }
542
670
  }
543
671
  }
672
+
673
+ /// Result of [`resolve_configs`].
674
+ pub struct ConfigResolution {
675
+ pub logger_config: edr_napi_core::logger::Config,
676
+ pub provider_config: edr_napi_core::provider::Config,
677
+ pub subscription_callback: edr_napi_core::subscription::Callback,
678
+ }
679
+
680
+ /// Helper function for resolving the provided N-API configs.
681
+ pub fn resolve_configs(
682
+ env: &napi::Env,
683
+ runtime: runtime::Handle,
684
+ provider_config: ProviderConfig,
685
+ logger_config: LoggerConfig,
686
+ subscription_config: SubscriptionConfig,
687
+ ) -> napi::Result<ConfigResolution> {
688
+ let provider_config = provider_config.resolve(env, runtime)?;
689
+ let logger_config = logger_config.resolve(env)?;
690
+
691
+ let subscription_config = edr_napi_core::subscription::Config::from(subscription_config);
692
+ let subscription_callback =
693
+ edr_napi_core::subscription::Callback::new(env, subscription_config.subscription_callback)?;
694
+
695
+ Ok(ConfigResolution {
696
+ logger_config,
697
+ provider_config,
698
+ subscription_callback,
699
+ })
700
+ }
package/src/context.rs CHANGED
@@ -1,11 +1,7 @@
1
1
  use std::sync::Arc;
2
2
 
3
- use edr_eth::HashMap;
4
- use edr_napi_core::{
5
- provider::{self, SyncProviderFactory},
6
- solidity,
7
- };
8
- use edr_solidity::contract_decoder::ContractDecoder;
3
+ use edr_napi_core::{provider::SyncProviderFactory, solidity};
4
+ use edr_primitives::HashMap;
9
5
  use edr_solidity_tests::{
10
6
  decode::RevertDecoder,
11
7
  multi_runner::{SuiteResultAndArtifactId, TestContract, TestContracts},
@@ -22,14 +18,15 @@ use napi_derive::napi;
22
18
  use tracing_subscriber::{prelude::*, EnvFilter, Registry};
23
19
 
24
20
  use crate::{
25
- config::{ProviderConfig, TracingConfigWithBuffers},
21
+ config::{resolve_configs, ConfigResolution, ProviderConfig, TracingConfigWithBuffers},
22
+ contract_decoder::ContractDecoder,
26
23
  logger::LoggerConfig,
27
24
  provider::{Provider, ProviderFactory},
28
25
  solidity_tests::{
29
26
  artifact::{Artifact, ArtifactId},
30
27
  config::SolidityTestRunnerConfigArgs,
31
28
  factory::SolidityTestRunnerFactory,
32
- test_results::SuiteResult,
29
+ test_results::{SolidityTestResult, SuiteResult},
33
30
  LinkingOutput,
34
31
  },
35
32
  subscription::SubscriptionConfig,
@@ -42,7 +39,7 @@ pub struct EdrContext {
42
39
 
43
40
  #[napi]
44
41
  impl EdrContext {
45
- #[doc = "Creates a new [`EdrContext`] instance. Should only be called once!"]
42
+ /// Creates a new [`EdrContext`] instance. Should only be called once!
46
43
  #[napi(catch_unwind, constructor)]
47
44
  pub fn new() -> napi::Result<Self> {
48
45
  let context = Context::new()?;
@@ -52,7 +49,7 @@ impl EdrContext {
52
49
  })
53
50
  }
54
51
 
55
- #[doc = "Constructs a new provider with the provided configuration."]
52
+ /// Constructs a new provider with the provided configuration.
56
53
  #[napi(catch_unwind, ts_return_type = "Promise<Provider>")]
57
54
  pub fn create_provider(
58
55
  &self,
@@ -61,7 +58,7 @@ impl EdrContext {
61
58
  provider_config: ProviderConfig,
62
59
  logger_config: LoggerConfig,
63
60
  subscription_config: SubscriptionConfig,
64
- tracing_config: TracingConfigWithBuffers,
61
+ contract_decoder: &ContractDecoder,
65
62
  ) -> napi::Result<JsObject> {
66
63
  let (deferred, promise) = env.create_deferred()?;
67
64
 
@@ -78,25 +75,18 @@ impl EdrContext {
78
75
  }
79
76
 
80
77
  let runtime = runtime::Handle::current();
81
- let provider_config =
82
- try_or_reject_promise!(provider_config.resolve(&env, runtime.clone()));
83
-
84
- let logger_config = try_or_reject_promise!(logger_config.resolve(&env));
85
-
86
- // TODO: https://github.com/NomicFoundation/edr/issues/760
87
- let build_info_config = try_or_reject_promise!(
88
- edr_solidity::artifacts::BuildInfoConfig::parse_from_buffers(
89
- (&edr_napi_core::solidity::config::TracingConfigWithBuffers::from(tracing_config))
90
- .into(),
91
- )
92
- .map_err(|error| napi::Error::from_reason(error.to_string()))
93
- );
94
-
95
- let contract_decoder = try_or_reject_promise!(ContractDecoder::new(&build_info_config)
96
- .map_or_else(
97
- |error| Err(napi::Error::from_reason(error.to_string())),
98
- |contract_decoder| Ok(Arc::new(contract_decoder))
99
- ));
78
+
79
+ let ConfigResolution {
80
+ logger_config,
81
+ provider_config,
82
+ subscription_callback,
83
+ } = try_or_reject_promise!(resolve_configs(
84
+ &env,
85
+ runtime.clone(),
86
+ provider_config,
87
+ logger_config,
88
+ subscription_config,
89
+ ));
100
90
 
101
91
  #[cfg(feature = "scenarios")]
102
92
  let scenario_file =
@@ -106,31 +96,33 @@ impl EdrContext {
106
96
  logger_config.enable,
107
97
  )));
108
98
 
109
- let builder = {
99
+ let factory = {
110
100
  // TODO: https://github.com/NomicFoundation/edr/issues/760
111
101
  // TODO: Don't block the JS event loop
112
102
  let context = runtime.block_on(async { self.inner.lock().await });
113
103
 
114
- try_or_reject_promise!(context.create_provider_builder(
115
- &env,
116
- &chain_type,
117
- provider_config,
118
- logger_config,
119
- subscription_config.into(),
120
- &contract_decoder,
121
- ))
104
+ try_or_reject_promise!(context.get_provider_factory(&chain_type))
122
105
  };
123
106
 
107
+ let contract_decoder = Arc::clone(contract_decoder.as_inner());
124
108
  runtime.clone().spawn_blocking(move || {
125
- let result = builder.build(runtime.clone()).map(|provider| {
126
- Provider::new(
127
- provider,
128
- runtime,
129
- contract_decoder,
130
- #[cfg(feature = "scenarios")]
131
- scenario_file,
109
+ let result = factory
110
+ .create_provider(
111
+ runtime.clone(),
112
+ provider_config,
113
+ logger_config,
114
+ subscription_callback,
115
+ Arc::clone(&contract_decoder),
132
116
  )
133
- });
117
+ .map(|provider| {
118
+ Provider::new(
119
+ provider,
120
+ runtime,
121
+ contract_decoder,
122
+ #[cfg(feature = "scenarios")]
123
+ scenario_file,
124
+ )
125
+ });
134
126
 
135
127
  deferred.resolve(|_env| result);
136
128
  });
@@ -138,7 +130,7 @@ impl EdrContext {
138
130
  Ok(promise)
139
131
  }
140
132
 
141
- #[doc = "Registers a new provider factory for the provided chain type."]
133
+ /// Registers a new provider factory for the provided chain type.
142
134
  #[napi(catch_unwind)]
143
135
  pub async fn register_provider_factory(
144
136
  &self,
@@ -161,14 +153,29 @@ impl EdrContext {
161
153
  Ok(())
162
154
  }
163
155
 
164
- #[doc = "Executes Solidity tests."]
165
- #[doc = ""]
166
- #[doc = "The function will return as soon as test execution is started."]
167
- #[doc = "The progress callback will be called with the results of each test"]
168
- #[doc = "suite. It is up to the caller to track how many times the callback"]
169
- #[doc = "is called to know when all tests are done."]
156
+ /// Executes Solidity tests
157
+ ///
158
+ /// The function will return a promise that resolves to a
159
+ /// [`SolidityTestResult`].
160
+ ///
161
+ /// Arguments:
162
+ /// - `chainType`: the same chain type that was passed to
163
+ /// `registerProviderFactory`.
164
+ /// - `artifacts`: the project's compilation output artifacts. It's
165
+ /// important to include include all artifacts here, otherwise cheatcodes
166
+ /// that access artifacts and other functionality (e.g. auto-linking, gas
167
+ /// reports) can break.
168
+ /// - `testSuites`: the test suite ids that specify which test suites to
169
+ /// execute. The test suite artifacts must be present in `artifacts`.
170
+ /// - `configArgs`: solidity test runner configuration. See the struct docs
171
+ /// for details.
172
+ /// - `tracingConfig`: the build infos used for stack trace generation.
173
+ /// These are lazily parsed and it's important that they're passed as
174
+ /// Uint8 arrays for performance.
175
+ /// - `onTestSuiteCompletedCallback`: The progress callback will be called
176
+ /// with the results of each test suite as soon as it finished executing.
170
177
  #[allow(clippy::too_many_arguments)]
171
- #[napi(catch_unwind, ts_return_type = "Promise<void>")]
178
+ #[napi(catch_unwind, ts_return_type = "Promise<SolidityTestResult>")]
172
179
  pub fn run_solidity_tests(
173
180
  &self,
174
181
  env: Env,
@@ -281,11 +288,12 @@ impl EdrContext {
281
288
 
282
289
  let include_traces = config.include_traces.into();
283
290
 
291
+ let runtime_for_factory = runtime.clone();
284
292
  let test_runner = try_or_reject_deferred!(runtime
285
293
  .clone()
286
294
  .spawn_blocking(move || {
287
295
  factory.create_test_runner(
288
- runtime,
296
+ runtime_for_factory,
289
297
  config,
290
298
  contracts,
291
299
  linking_output.known_contracts,
@@ -297,30 +305,40 @@ impl EdrContext {
297
305
  .await
298
306
  .expect("Failed to join test runner factory thread"));
299
307
 
300
- let () = try_or_reject_deferred!(test_runner.run_tests(
301
- test_filter,
302
- Arc::new(
303
- move |SuiteResultAndArtifactId {
304
- artifact_id,
305
- result,
306
- }| {
307
- let suite_result = SuiteResult::new(artifact_id, result, include_traces);
308
-
309
- let status = on_test_suite_completed_callback
310
- .call(suite_result, ThreadsafeFunctionCallMode::Blocking);
311
-
312
- // This should always succeed since we're using an unbounded queue. We add
313
- // an assertion for completeness.
314
- assert_eq!(
308
+ let runtime_for_runner = runtime.clone();
309
+ let test_result = try_or_reject_deferred!(runtime
310
+ .clone()
311
+ .spawn_blocking(move || {
312
+ test_runner.run_tests(
313
+ runtime_for_runner,
314
+ test_filter,
315
+ Arc::new(
316
+ move |SuiteResultAndArtifactId {
317
+ artifact_id,
318
+ result,
319
+ }| {
320
+ let suite_result =
321
+ SuiteResult::new(artifact_id, result, include_traces);
322
+
323
+ let status = on_test_suite_completed_callback
324
+ .call(suite_result, ThreadsafeFunctionCallMode::Blocking);
325
+
326
+ // This should always succeed since we're using an unbounded queue.
327
+ // We add an assertion for
328
+ // completeness.
329
+ assert_eq!(
315
330
  status,
316
331
  napi::Status::Ok,
317
332
  "Failed to call on_test_suite_completed_callback with status: {status}"
318
333
  );
319
- }
320
- ),
321
- ));
334
+ },
335
+ ),
336
+ )
337
+ })
338
+ .await
339
+ .expect("Failed to join test runner thread"));
322
340
 
323
- deferred.resolve(move |_env| Ok(()));
341
+ deferred.resolve(move |_env| Ok(SolidityTestResult::from(test_result)));
324
342
  });
325
343
 
326
344
  Ok(promise)
@@ -399,23 +417,12 @@ impl Context {
399
417
 
400
418
  /// Tries to create a new provider for the provided chain type and
401
419
  /// configuration.
402
- pub fn create_provider_builder(
420
+ pub fn get_provider_factory(
403
421
  &self,
404
- env: &napi::Env,
405
422
  chain_type: &str,
406
- provider_config: edr_napi_core::provider::Config,
407
- logger_config: edr_napi_core::logger::Config,
408
- subscription_config: edr_napi_core::subscription::Config,
409
- contract_decoder: &Arc<ContractDecoder>,
410
- ) -> napi::Result<Box<dyn provider::Builder>> {
423
+ ) -> napi::Result<Arc<dyn SyncProviderFactory>> {
411
424
  if let Some(factory) = self.provider_factories.get(chain_type) {
412
- factory.create_provider_builder(
413
- env,
414
- provider_config,
415
- logger_config,
416
- subscription_config,
417
- contract_decoder.clone(),
418
- )
425
+ Ok(Arc::clone(factory))
419
426
  } else {
420
427
  Err(napi::Error::new(
421
428
  napi::Status::GenericFailure,
@@ -0,0 +1,57 @@
1
+ use std::sync::Arc;
2
+
3
+ use napi_derive::napi;
4
+
5
+ use crate::config::TracingConfigWithBuffers;
6
+
7
+ #[napi]
8
+ pub struct ContractDecoder {
9
+ inner: Arc<edr_solidity::contract_decoder::ContractDecoder>,
10
+ }
11
+
12
+ #[napi]
13
+ impl ContractDecoder {
14
+ #[doc = "Creates an empty instance."]
15
+ #[napi(constructor, catch_unwind)]
16
+ // Following TS convention for the constructor without arguments to be `new()`.
17
+ #[allow(clippy::new_without_default)]
18
+ pub fn new() -> Self {
19
+ Self {
20
+ inner: Arc::new(edr_solidity::contract_decoder::ContractDecoder::default()),
21
+ }
22
+ }
23
+
24
+ #[doc = "Creates a new instance with the provided configuration."]
25
+ #[napi(factory, catch_unwind)]
26
+ pub fn with_contracts(config: TracingConfigWithBuffers) -> napi::Result<Self> {
27
+ let build_info_config = edr_solidity::artifacts::BuildInfoConfig::parse_from_buffers(
28
+ (&edr_napi_core::solidity::config::TracingConfigWithBuffers::from(config)).into(),
29
+ )
30
+ .map_err(|error| napi::Error::from_reason(error.to_string()))?;
31
+
32
+ let contract_decoder =
33
+ edr_solidity::contract_decoder::ContractDecoder::new(&build_info_config).map_or_else(
34
+ |error| Err(napi::Error::from_reason(error.to_string())),
35
+ |contract_decoder| Ok(Arc::new(contract_decoder)),
36
+ )?;
37
+
38
+ Ok(Self {
39
+ inner: contract_decoder,
40
+ })
41
+ }
42
+ }
43
+
44
+ impl ContractDecoder {
45
+ /// Returns a reference to the inner contract decoder.
46
+ pub fn as_inner(&self) -> &Arc<edr_solidity::contract_decoder::ContractDecoder> {
47
+ &self.inner
48
+ }
49
+ }
50
+
51
+ impl From<Arc<edr_solidity::contract_decoder::ContractDecoder>> for ContractDecoder {
52
+ fn from(contract_decoder: Arc<edr_solidity::contract_decoder::ContractDecoder>) -> Self {
53
+ Self {
54
+ inner: contract_decoder,
55
+ }
56
+ }
57
+ }
@@ -3,6 +3,8 @@ use std::collections::HashMap;
3
3
  use napi::bindgen_prelude::{BigInt, Uint8Array};
4
4
  use napi_derive::napi;
5
5
 
6
+ // False positive: imported by HH2
7
+ #[allow(dead_code)]
6
8
  #[napi(object)]
7
9
  pub struct DebugTraceResult {
8
10
  pub pass: bool,