@nomicfoundation/edr 0.12.0-next.6 → 0.12.0-next.7

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/index.d.ts CHANGED
@@ -169,11 +169,11 @@ export interface BaseFeeParamActivation {
169
169
  elasticityMultiplier: bigint
170
170
  }
171
171
  export interface BaseFeeActivationByBlockNumber {
172
- /** The block number at which the base_fee_params is activated */
172
+ /** The block number at which the `base_fee_params` is activated */
173
173
  blockNumber: bigint
174
174
  }
175
175
  export interface BaseFeeActivationByHardfork {
176
- /** The hardfork at which the base_fee_params is activated */
176
+ /** The hardfork at which the `base_fee_params` is activated */
177
177
  hardfork: string
178
178
  }
179
179
  /** Specification of a chain with possible overrides. */
@@ -273,7 +273,7 @@ export interface ProviderConfig {
273
273
  * EIP-1559 base fee parameters activations to be used to calculate the
274
274
  * block base fee.
275
275
  *
276
- * Provide an ordered list of base_fee_params to be
276
+ * Provide an ordered list of `base_fee_params` to be
277
277
  * used starting from the specified activation point (hardfork or block
278
278
  * number).
279
279
  * If not provided, the default values from the chain spec
@@ -644,7 +644,7 @@ export interface SolidityTestRunnerConfigArgs {
644
644
  disableBlockGasLimit?: boolean
645
645
  /**
646
646
  * The memory limit of the EVM in bytes.
647
- * Defaults to 33_554_432 (2^25 = 32MiB).
647
+ * Defaults to `33_554_432` (2^25 = 32MiB).
648
648
  */
649
649
  memoryLimit?: bigint
650
650
  /**
@@ -689,6 +689,8 @@ export interface SolidityTestRunnerConfigArgs {
689
689
  * config value is set, then the fuzz config value will be used.
690
690
  */
691
691
  invariant?: InvariantConfigArgs
692
+ /** Whether to collect stack traces. */
693
+ collectStackTraces?: CollectStackTraces
692
694
  /**
693
695
  * Controls which test results should include execution traces. Defaults to
694
696
  * None.
@@ -865,6 +867,19 @@ export interface AddressLabel {
865
867
  /** The label to assign to the address */
866
868
  label: string
867
869
  }
870
+ /** A type that controls when stack traces are collected. */
871
+ export enum CollectStackTraces {
872
+ /** Always collects stack traces, adding performance overhead. */
873
+ Always = 0,
874
+ /**
875
+ * Only collects stack traces upon failure, re-executing the test. This
876
+ * minimizes performance overhead.
877
+ *
878
+ * Not all tests can be re-executed since certain cheatcodes contain
879
+ * non-deterministic side-effects.
880
+ */
881
+ OnFailure = 1
882
+ }
868
883
  /**
869
884
  * Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
870
885
  * controls execution trace decoding and inclusion in test results.
@@ -948,21 +963,21 @@ export enum TestStatus {
948
963
  /**Test skipped */
949
964
  Skipped = 'Skipped'
950
965
  }
951
- /** See [edr_solidity_tests::result::TestKind::Standard] */
966
+ /** See [`edr_solidity_tests::result::TestKind::Standard`] */
952
967
  export interface StandardTestKind {
953
968
  /** The gas consumed by the test. */
954
969
  readonly consumedGas: bigint
955
970
  }
956
- /** See [edr_solidity_tests::result::TestKind::Fuzz] */
971
+ /** See [`edr_solidity_tests::result::TestKind::Fuzz`] */
957
972
  export interface FuzzTestKind {
958
- /** See [edr_solidity_tests::result::TestKind::Fuzz] */
973
+ /** See [`edr_solidity_tests::result::TestKind::Fuzz`] */
959
974
  readonly runs: bigint
960
- /** See [edr_solidity_tests::result::TestKind::Fuzz] */
975
+ /** See [`edr_solidity_tests::result::TestKind::Fuzz`] */
961
976
  readonly meanGas: bigint
962
- /** See [edr_solidity_tests::result::TestKind::Fuzz] */
977
+ /** See [`edr_solidity_tests::result::TestKind::Fuzz`] */
963
978
  readonly medianGas: bigint
964
979
  }
965
- /** See [edr_solidity_tests::fuzz::FuzzCase] */
980
+ /** See [`edr_solidity_tests::fuzz::FuzzCase`] */
966
981
  export interface FuzzCase {
967
982
  /** The calldata used for this fuzz test */
968
983
  readonly calldata: Uint8Array
@@ -971,13 +986,13 @@ export interface FuzzCase {
971
986
  /** The initial gas stipend for the transaction */
972
987
  readonly stipend: bigint
973
988
  }
974
- /** See [edr_solidity_tests::result::TestKind::Invariant] */
989
+ /** See [`edr_solidity_tests::result::TestKind::Invariant`] */
975
990
  export interface InvariantTestKind {
976
- /** See [edr_solidity_tests::result::TestKind::Invariant] */
991
+ /** See [`edr_solidity_tests::result::TestKind::Invariant`] */
977
992
  readonly runs: bigint
978
- /** See [edr_solidity_tests::result::TestKind::Invariant] */
993
+ /** See [`edr_solidity_tests::result::TestKind::Invariant`] */
979
994
  readonly calls: bigint
980
- /** See [edr_solidity_tests::result::TestKind::Invariant] */
995
+ /** See [`edr_solidity_tests::result::TestKind::Invariant`] */
981
996
  readonly reverts: bigint
982
997
  }
983
998
  /**
@@ -990,19 +1005,19 @@ export interface CounterExampleSequence {
990
1005
  /** The shrunk counterexample sequence. */
991
1006
  sequence: Array<BaseCounterExample>
992
1007
  }
993
- /** See [edr_solidity_tests::fuzz::BaseCounterExample] */
1008
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample`] */
994
1009
  export interface BaseCounterExample {
995
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::sender] */
1010
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::sender`] */
996
1011
  readonly sender?: Uint8Array
997
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::addr] */
1012
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::addr`] */
998
1013
  readonly address?: Uint8Array
999
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::calldata] */
1014
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::calldata`] */
1000
1015
  readonly calldata: Uint8Array
1001
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::contract_name] */
1016
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::contract_name`] */
1002
1017
  readonly contractName?: string
1003
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::signature] */
1018
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::signature`] */
1004
1019
  readonly signature?: string
1005
- /** See [edr_solidity_tests::fuzz::BaseCounterExample::args] */
1020
+ /** See [`edr_solidity_tests::fuzz::BaseCounterExample::args`] */
1006
1021
  readonly args?: string
1007
1022
  }
1008
1023
  /**
@@ -1351,7 +1366,7 @@ export declare class EdrContext {
1351
1366
  /**Creates a new [`EdrContext`] instance. Should only be called once! */
1352
1367
  constructor()
1353
1368
  /**Constructs a new provider with the provided configuration. */
1354
- createProvider(chainType: string, providerConfig: ProviderConfig, loggerConfig: LoggerConfig, subscriptionConfig: SubscriptionConfig, tracingConfig: TracingConfigWithBuffers): Promise<Provider>
1369
+ createProvider(chainType: string, providerConfig: ProviderConfig, loggerConfig: LoggerConfig, subscriptionConfig: SubscriptionConfig, contractDecoder: ContractDecoder): Promise<Provider>
1355
1370
  /**Registers a new provider factory for the provided chain type. */
1356
1371
  registerProviderFactory(chainType: string, factory: ProviderFactory): Promise<void>
1357
1372
  registerSolidityTestRunnerFactory(chainType: string, factory: SolidityTestRunnerFactory): Promise<void>
@@ -1365,6 +1380,12 @@ export declare class EdrContext {
1365
1380
  */
1366
1381
  runSolidityTests(chainType: string, artifacts: Array<Artifact>, testSuites: Array<ArtifactId>, configArgs: SolidityTestRunnerConfigArgs, tracingConfig: TracingConfigWithBuffers, onTestSuiteCompletedCallback: (result: SuiteResult) => void): Promise<void>
1367
1382
  }
1383
+ export declare class ContractDecoder {
1384
+ /**Creates an empty instance. */
1385
+ constructor()
1386
+ /**Creates a new instance with the provided configuration. */
1387
+ static withContracts(config: TracingConfigWithBuffers): ContractDecoder
1388
+ }
1368
1389
  export declare class Precompile {
1369
1390
  /** Returns the address of the precompile. */
1370
1391
  get address(): Uint8Array
@@ -1385,7 +1406,9 @@ export declare class Provider {
1385
1406
  *
1386
1407
  *For internal use only. Support for this method may be removed in the future.
1387
1408
  */
1388
- addCompilationResult(solcVersion: string, compilerInput: any, compilerOutput: any): Promise<boolean>
1409
+ addCompilationResult(solcVersion: string, compilerInput: any, compilerOutput: any): Promise<void>
1410
+ /**Retrieves the instance's contract decoder. */
1411
+ contractDecoder(): ContractDecoder
1389
1412
  /**Handles a JSON-RPC request and returns a JSON-RPC response. */
1390
1413
  handleRequest(request: string): Promise<Response>
1391
1414
  setCallOverrideCallback(callOverrideCallback: (contract_address: ArrayBuffer, data: ArrayBuffer) => Promise<CallOverrideResult | undefined>): Promise<void>
@@ -1398,35 +1421,35 @@ export declare class Provider {
1398
1421
  setVerboseTracing(verboseTracing: boolean): Promise<void>
1399
1422
  }
1400
1423
  export declare class SolidityTestRunnerFactory { }
1401
- /** See [edr_solidity_tests::result::SuiteResult] */
1424
+ /** See [`edr_solidity_tests::result::SuiteResult`] */
1402
1425
  export declare class SuiteResult {
1403
1426
  /**
1404
1427
  * The artifact id can be used to match input to result in the progress
1405
1428
  * callback
1406
1429
  */
1407
1430
  readonly id: ArtifactId
1408
- /** See [edr_solidity_tests::result::SuiteResult::duration] */
1431
+ /** See [`edr_solidity_tests::result::SuiteResult::duration`] */
1409
1432
  readonly durationNs: bigint
1410
- /** See [edr_solidity_tests::result::SuiteResult::test_results] */
1433
+ /** See [`edr_solidity_tests::result::SuiteResult::test_results`] */
1411
1434
  readonly testResults: Array<TestResult>
1412
- /** See [edr_solidity_tests::result::SuiteResult::warnings] */
1435
+ /** See [`edr_solidity_tests::result::SuiteResult::warnings`] */
1413
1436
  readonly warnings: Array<string>
1414
1437
  }
1415
- /** See [edr_solidity_tests::result::TestResult] */
1438
+ /** See [`edr_solidity_tests::result::TestResult`] */
1416
1439
  export declare class TestResult {
1417
1440
  /** The name of the test. */
1418
1441
  readonly name: string
1419
- /** See [edr_solidity_tests::result::TestResult::status] */
1442
+ /** See [`edr_solidity_tests::result::TestResult::status`] */
1420
1443
  readonly status: TestStatus
1421
- /** See [edr_solidity_tests::result::TestResult::reason] */
1444
+ /** See [`edr_solidity_tests::result::TestResult::reason`] */
1422
1445
  readonly reason?: string
1423
- /** See [edr_solidity_tests::result::TestResult::counterexample] */
1446
+ /** See [`edr_solidity_tests::result::TestResult::counterexample`] */
1424
1447
  readonly counterexample?: BaseCounterExample | CounterExampleSequence
1425
- /** See [edr_solidity_tests::result::TestResult::decoded_logs] */
1448
+ /** See [`edr_solidity_tests::result::TestResult::decoded_logs`] */
1426
1449
  readonly decodedLogs: Array<string>
1427
- /** See [edr_solidity_tests::result::TestResult::kind] */
1450
+ /** See [`edr_solidity_tests::result::TestResult::kind`] */
1428
1451
  readonly kind: StandardTestKind | FuzzTestKind | InvariantTestKind
1429
- /** See [edr_solidity_tests::result::TestResult::duration] */
1452
+ /** See [`edr_solidity_tests::result::TestResult::duration`] */
1430
1453
  readonly durationNs: bigint
1431
1454
  /**
1432
1455
  * Groups of value snapshot entries (incl. gas).
package/index.js CHANGED
@@ -310,7 +310,7 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { GENERIC_CHAIN_TYPE, genericChainProviderFactory, L1_CHAIN_TYPE, l1GenesisState, l1ProviderFactory, SpecId, l1HardforkFromString, l1HardforkToString, l1HardforkLatest, FRONTIER, FRONTIER_THAWING, HOMESTEAD, DAO_FORK, TANGERINE, SPURIOUS_DRAGON, BYZANTIUM, CONSTANTINOPLE, PETERSBURG, ISTANBUL, MUIR_GLACIER, BERLIN, LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN, PRAGUE, OpHardfork, opHardforkFromString, opHardforkToString, opLatestHardfork, OP_CHAIN_TYPE, opGenesisState, opProviderFactory, BEDROCK, REGOLITH, CANYON, ECOTONE, FJORD, GRANITE, HOLOCENE, ISTHMUS, MineOrdering, EdrContext, addStatementCoverageInstrumentation, Precompile, precompileP256Verify, ProviderFactory, Response, Provider, SuccessReason, ExceptionalHalt, CachedChains, CachedEndpoints, FsAccessPermission, IncludeTraces, SolidityTestRunnerFactory, l1SolidityTestRunnerFactory, opSolidityTestRunnerFactory, SuiteResult, TestResult, TestStatus, CallKind, LogKind, linkHexStringBytecode, printStackTrace, Exit, ExitCode, BytecodeWrapper, ContractFunctionType, ReturnData, StackTraceEntryType, stackTraceEntryTypeToString, FALLBACK_FUNCTION_NAME, RECEIVE_FUNCTION_NAME, CONSTRUCTOR_FUNCTION_NAME, UNRECOGNIZED_FUNCTION_NAME, UNKNOWN_FUNCTION_NAME, PRECOMPILE_FUNCTION_NAME, UNRECOGNIZED_CONTRACT_NAME, RawTrace, getLatestSupportedSolcVersion } = nativeBinding
313
+ const { GENERIC_CHAIN_TYPE, genericChainProviderFactory, L1_CHAIN_TYPE, l1GenesisState, l1ProviderFactory, SpecId, l1HardforkFromString, l1HardforkToString, l1HardforkLatest, FRONTIER, FRONTIER_THAWING, HOMESTEAD, DAO_FORK, TANGERINE, SPURIOUS_DRAGON, BYZANTIUM, CONSTANTINOPLE, PETERSBURG, ISTANBUL, MUIR_GLACIER, BERLIN, LONDON, ARROW_GLACIER, GRAY_GLACIER, MERGE, SHANGHAI, CANCUN, PRAGUE, OpHardfork, opHardforkFromString, opHardforkToString, opLatestHardfork, OP_CHAIN_TYPE, opGenesisState, opProviderFactory, BEDROCK, REGOLITH, CANYON, ECOTONE, FJORD, GRANITE, HOLOCENE, ISTHMUS, MineOrdering, EdrContext, ContractDecoder, addStatementCoverageInstrumentation, Precompile, precompileP256Verify, ProviderFactory, Response, Provider, SuccessReason, ExceptionalHalt, CachedChains, CachedEndpoints, FsAccessPermission, CollectStackTraces, IncludeTraces, SolidityTestRunnerFactory, l1SolidityTestRunnerFactory, opSolidityTestRunnerFactory, SuiteResult, TestResult, TestStatus, CallKind, LogKind, linkHexStringBytecode, printStackTrace, Exit, ExitCode, BytecodeWrapper, ContractFunctionType, ReturnData, StackTraceEntryType, stackTraceEntryTypeToString, FALLBACK_FUNCTION_NAME, RECEIVE_FUNCTION_NAME, CONSTRUCTOR_FUNCTION_NAME, UNRECOGNIZED_FUNCTION_NAME, UNKNOWN_FUNCTION_NAME, PRECOMPILE_FUNCTION_NAME, UNRECOGNIZED_CONTRACT_NAME, RawTrace, getLatestSupportedSolcVersion } = nativeBinding
314
314
 
315
315
  module.exports.GENERIC_CHAIN_TYPE = GENERIC_CHAIN_TYPE
316
316
  module.exports.genericChainProviderFactory = genericChainProviderFactory
@@ -357,6 +357,7 @@ module.exports.HOLOCENE = HOLOCENE
357
357
  module.exports.ISTHMUS = ISTHMUS
358
358
  module.exports.MineOrdering = MineOrdering
359
359
  module.exports.EdrContext = EdrContext
360
+ module.exports.ContractDecoder = ContractDecoder
360
361
  module.exports.addStatementCoverageInstrumentation = addStatementCoverageInstrumentation
361
362
  module.exports.Precompile = Precompile
362
363
  module.exports.precompileP256Verify = precompileP256Verify
@@ -368,6 +369,7 @@ module.exports.ExceptionalHalt = ExceptionalHalt
368
369
  module.exports.CachedChains = CachedChains
369
370
  module.exports.CachedEndpoints = CachedEndpoints
370
371
  module.exports.FsAccessPermission = FsAccessPermission
372
+ module.exports.CollectStackTraces = CollectStackTraces
371
373
  module.exports.IncludeTraces = IncludeTraces
372
374
  module.exports.SolidityTestRunnerFactory = SolidityTestRunnerFactory
373
375
  module.exports.l1SolidityTestRunnerFactory = l1SolidityTestRunnerFactory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomicfoundation/edr",
3
- "version": "0.12.0-next.6",
3
+ "version": "0.12.0-next.7",
4
4
  "devDependencies": {
5
5
  "@napi-rs/cli": "^2.18.4",
6
6
  "@nomicfoundation/ethereumjs-util": "^9.0.4",
@@ -59,13 +59,13 @@
59
59
  "repository": "NomicFoundation/edr.git",
60
60
  "types": "index.d.ts",
61
61
  "optionalDependencies": {
62
- "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.6",
63
- "@nomicfoundation/edr-darwin-x64": "0.12.0-next.6",
64
- "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.6",
65
- "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.6",
66
- "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.6",
67
- "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.6",
68
- "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.6"
62
+ "@nomicfoundation/edr-darwin-arm64": "0.12.0-next.7",
63
+ "@nomicfoundation/edr-darwin-x64": "0.12.0-next.7",
64
+ "@nomicfoundation/edr-linux-arm64-gnu": "0.12.0-next.7",
65
+ "@nomicfoundation/edr-linux-arm64-musl": "0.12.0-next.7",
66
+ "@nomicfoundation/edr-linux-x64-gnu": "0.12.0-next.7",
67
+ "@nomicfoundation/edr-linux-x64-musl": "0.12.0-next.7",
68
+ "@nomicfoundation/edr-win32-x64-msvc": "0.12.0-next.7"
69
69
  },
70
70
  "scripts": {
71
71
  "artifacts": "napi artifacts",
package/src/config.rs CHANGED
@@ -2,7 +2,6 @@ use core::fmt::{Debug, Display};
2
2
  use std::{
3
3
  num::NonZeroU64,
4
4
  path::PathBuf,
5
- sync::Arc,
6
5
  time::{Duration, SystemTime},
7
6
  };
8
7
 
@@ -10,7 +9,6 @@ use edr_coverage::reporter::SyncOnCollectedCoverageCallback;
10
9
  use edr_eip1559::{BaseFeeActivation, ConstantBaseFeeParams};
11
10
  use edr_eth::{Bytes, HashMap, HashSet};
12
11
  use edr_signer::{secret_key_from_str, SecretKey};
13
- use edr_solidity::contract_decoder::ContractDecoder;
14
12
  use napi::{
15
13
  bindgen_prelude::{BigInt, Promise, Reference, Uint8Array},
16
14
  threadsafe_function::{
@@ -36,12 +34,12 @@ pub struct BaseFeeParamActivation {
36
34
 
37
35
  #[napi(object)]
38
36
  pub struct BaseFeeActivationByBlockNumber {
39
- /// The block number at which the base_fee_params is activated
37
+ /// The block number at which the `base_fee_params` is activated
40
38
  pub block_number: BigInt,
41
39
  }
42
40
  #[napi(object)]
43
41
  pub struct BaseFeeActivationByHardfork {
44
- /// The hardfork at which the base_fee_params is activated
42
+ /// The hardfork at which the `base_fee_params` is activated
45
43
  pub hardfork: String,
46
44
  }
47
45
 
@@ -187,7 +185,7 @@ pub struct ProviderConfig {
187
185
  /// EIP-1559 base fee parameters activations to be used to calculate the
188
186
  /// block base fee.
189
187
  ///
190
- /// Provide an ordered list of base_fee_params to be
188
+ /// Provide an ordered list of `base_fee_params` to be
191
189
  /// used starting from the specified activation point (hardfork or block
192
190
  /// number).
193
191
  /// If not provided, the default values from the chain spec
@@ -606,7 +604,6 @@ impl From<BuildInfoAndOutput> for edr_napi_core::solidity::config::BuildInfoAndO
606
604
 
607
605
  /// Result of [`resolve_configs`].
608
606
  pub struct ConfigResolution {
609
- pub contract_decoder: Arc<ContractDecoder>,
610
607
  pub logger_config: edr_napi_core::logger::Config,
611
608
  pub provider_config: edr_napi_core::provider::Config,
612
609
  pub subscription_callback: edr_napi_core::subscription::Callback,
@@ -619,28 +616,15 @@ pub fn resolve_configs(
619
616
  provider_config: ProviderConfig,
620
617
  logger_config: LoggerConfig,
621
618
  subscription_config: SubscriptionConfig,
622
- tracing_config: TracingConfigWithBuffers,
623
619
  ) -> napi::Result<ConfigResolution> {
624
620
  let provider_config = provider_config.resolve(env, runtime)?;
625
621
  let logger_config = logger_config.resolve(env)?;
626
622
 
627
- // TODO: https://github.com/NomicFoundation/edr/issues/760
628
- let build_info_config = edr_solidity::artifacts::BuildInfoConfig::parse_from_buffers(
629
- (&edr_napi_core::solidity::config::TracingConfigWithBuffers::from(tracing_config)).into(),
630
- )
631
- .map_err(|error| napi::Error::from_reason(error.to_string()))?;
632
-
633
- let contract_decoder = ContractDecoder::new(&build_info_config).map_or_else(
634
- |error| Err(napi::Error::from_reason(error.to_string())),
635
- |contract_decoder| Ok(Arc::new(contract_decoder)),
636
- )?;
637
-
638
623
  let subscription_config = edr_napi_core::subscription::Config::from(subscription_config);
639
624
  let subscription_callback =
640
625
  edr_napi_core::subscription::Callback::new(env, subscription_config.subscription_callback)?;
641
626
 
642
627
  Ok(ConfigResolution {
643
- contract_decoder,
644
628
  logger_config,
645
629
  provider_config,
646
630
  subscription_callback,
package/src/context.rs CHANGED
@@ -19,6 +19,7 @@ use tracing_subscriber::{prelude::*, EnvFilter, Registry};
19
19
 
20
20
  use crate::{
21
21
  config::{resolve_configs, ConfigResolution, ProviderConfig, TracingConfigWithBuffers},
22
+ contract_decoder::ContractDecoder,
22
23
  logger::LoggerConfig,
23
24
  provider::{Provider, ProviderFactory},
24
25
  solidity_tests::{
@@ -57,7 +58,7 @@ impl EdrContext {
57
58
  provider_config: ProviderConfig,
58
59
  logger_config: LoggerConfig,
59
60
  subscription_config: SubscriptionConfig,
60
- tracing_config: TracingConfigWithBuffers,
61
+ contract_decoder: &ContractDecoder,
61
62
  ) -> napi::Result<JsObject> {
62
63
  let (deferred, promise) = env.create_deferred()?;
63
64
 
@@ -76,7 +77,6 @@ impl EdrContext {
76
77
  let runtime = runtime::Handle::current();
77
78
 
78
79
  let ConfigResolution {
79
- contract_decoder,
80
80
  logger_config,
81
81
  provider_config,
82
82
  subscription_callback,
@@ -86,7 +86,6 @@ impl EdrContext {
86
86
  provider_config,
87
87
  logger_config,
88
88
  subscription_config,
89
- tracing_config
90
89
  ));
91
90
 
92
91
  #[cfg(feature = "scenarios")]
@@ -105,6 +104,7 @@ impl EdrContext {
105
104
  try_or_reject_promise!(context.get_provider_factory(&chain_type))
106
105
  };
107
106
 
107
+ let contract_decoder = Arc::clone(contract_decoder.as_inner());
108
108
  runtime.clone().spawn_blocking(move || {
109
109
  let result = factory
110
110
  .create_provider(
@@ -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,
package/src/lib.rs CHANGED
@@ -17,6 +17,8 @@ pub mod chains;
17
17
  pub mod config;
18
18
  /// Types related to an EDR N-API context.
19
19
  pub mod context;
20
+ /// Types for decoding smart contract data.
21
+ pub mod contract_decoder;
20
22
  mod debug_trace;
21
23
  /// Types and functions related to code coverage instrumentation.
22
24
  pub mod instrument;
package/src/mock/time.rs CHANGED
@@ -11,7 +11,8 @@ use napi_derive::napi;
11
11
 
12
12
  use crate::{
13
13
  cast::TryCast as _,
14
- config::{resolve_configs, ConfigResolution, ProviderConfig, TracingConfigWithBuffers},
14
+ config::{resolve_configs, ConfigResolution, ProviderConfig},
15
+ contract_decoder::ContractDecoder,
15
16
  logger::LoggerConfig,
16
17
  provider::Provider,
17
18
  subscription::SubscriptionConfig,
@@ -50,7 +51,7 @@ pub fn create_provider_with_mock_timer(
50
51
  provider_config: ProviderConfig,
51
52
  logger_config: LoggerConfig,
52
53
  subscription_config: SubscriptionConfig,
53
- tracing_config: TracingConfigWithBuffers,
54
+ contract_decoder: &ContractDecoder,
54
55
  time: &MockTime,
55
56
  ) -> napi::Result<JsObject> {
56
57
  let (deferred, promise) = env.create_deferred()?;
@@ -70,7 +71,6 @@ pub fn create_provider_with_mock_timer(
70
71
  let runtime = runtime::Handle::current();
71
72
 
72
73
  let ConfigResolution {
73
- contract_decoder,
74
74
  logger_config,
75
75
  provider_config,
76
76
  subscription_callback,
@@ -80,9 +80,9 @@ pub fn create_provider_with_mock_timer(
80
80
  provider_config,
81
81
  logger_config,
82
82
  subscription_config,
83
- tracing_config,
84
83
  ));
85
84
 
85
+ let contract_decoder = Arc::clone(contract_decoder.as_inner());
86
86
  let timer = Arc::clone(&time.inner);
87
87
 
88
88
  runtime.clone().spawn_blocking(move || {
@@ -112,7 +112,7 @@ pub fn create_provider_with_mock_timer(
112
112
  subscription_callback.call(event);
113
113
  }),
114
114
  provider_config,
115
- contract_decoder.clone(),
115
+ Arc::clone(&contract_decoder),
116
116
  timer,
117
117
  )
118
118
  .map_err(|error| napi::Error::from_reason(error.to_string()))?;
package/src/mock.rs CHANGED
@@ -23,15 +23,6 @@ impl MockProvider {
23
23
  }
24
24
 
25
25
  impl SyncProvider for MockProvider {
26
- fn add_compilation_result(
27
- &self,
28
- _solc_version: String,
29
- _compiler_input: edr_solidity::artifacts::CompilerInput,
30
- _compiler_output: edr_solidity::artifacts::CompilerOutput,
31
- ) -> napi::Result<bool> {
32
- Ok(false) // Mock provider does not handle compilation results
33
- }
34
-
35
26
  fn handle_request(
36
27
  &self,
37
28
  _request: String,
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
  >,
@@ -54,8 +54,8 @@ impl Provider {
54
54
  solc_version: String,
55
55
  compiler_input: serde_json::Value,
56
56
  compiler_output: serde_json::Value,
57
- ) -> napi::Result<bool> {
58
- let provider = self.provider.clone();
57
+ ) -> napi::Result<()> {
58
+ let contract_decoder = self.contract_decoder.clone();
59
59
 
60
60
  self.runtime
61
61
  .spawn_blocking(move || {
@@ -65,12 +65,33 @@ impl Provider {
65
65
  let compiler_output = serde_json::from_value(compiler_output)
66
66
  .map_err(|error| napi::Error::from_reason(error.to_string()))?;
67
67
 
68
- provider.add_compilation_result(solc_version, compiler_input, compiler_output)
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(())
69
84
  })
70
85
  .await
71
86
  .map_err(|error| napi::Error::new(Status::GenericFailure, error.to_string()))?
72
87
  }
73
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
+
74
95
  #[doc = "Handles a JSON-RPC request and returns a JSON-RPC response."]
75
96
  #[napi(catch_unwind)]
76
97
  pub async fn handle_request(&self, request: String) -> napi::Result<Response> {
@@ -109,7 +109,7 @@ pub struct SolidityTestRunnerConfigArgs {
109
109
  /// Defaults to false.
110
110
  pub disable_block_gas_limit: Option<bool>,
111
111
  /// The memory limit of the EVM in bytes.
112
- /// Defaults to 33_554_432 (2^25 = 32MiB).
112
+ /// Defaults to `33_554_432` (2^25 = 32MiB).
113
113
  #[serde(serialize_with = "serialize_optional_bigint_as_struct")]
114
114
  pub memory_limit: Option<BigInt>,
115
115
  /// The predeploys applied in local mode. Defaults to no predeploys.
@@ -143,6 +143,8 @@ pub struct SolidityTestRunnerConfigArgs {
143
143
  /// If an invariant config setting is not set, but a corresponding fuzz
144
144
  /// config value is set, then the fuzz config value will be used.
145
145
  pub invariant: Option<InvariantConfigArgs>,
146
+ /// Whether to collect stack traces.
147
+ pub collect_stack_traces: Option<CollectStackTraces>,
146
148
  /// Controls which test results should include execution traces. Defaults to
147
149
  /// None.
148
150
  pub include_traces: Option<IncludeTraces>,
@@ -194,6 +196,7 @@ impl SolidityTestRunnerConfigArgs {
194
196
  prompt_timeout,
195
197
  fuzz,
196
198
  invariant,
199
+ collect_stack_traces,
197
200
  include_traces,
198
201
  observability,
199
202
  test_pattern,
@@ -296,6 +299,10 @@ impl SolidityTestRunnerConfigArgs {
296
299
  cheatcode,
297
300
  fuzz,
298
301
  invariant,
302
+ collect_stack_traces: collect_stack_traces.map_or(
303
+ edr_solidity_tests::CollectStackTraces::OnFailure,
304
+ edr_solidity_tests::CollectStackTraces::from,
305
+ ),
299
306
  on_collected_coverage_fn,
300
307
  test_pattern,
301
308
  };
@@ -721,6 +728,29 @@ pub struct AddressLabel {
721
728
  pub label: String,
722
729
  }
723
730
 
731
+ /// A type that controls when stack traces are collected.
732
+ #[napi]
733
+ #[derive(Debug, serde::Serialize)]
734
+ pub enum CollectStackTraces {
735
+ /// Always collects stack traces, adding performance overhead.
736
+ Always,
737
+ /// Only collects stack traces upon failure, re-executing the test. This
738
+ /// minimizes performance overhead.
739
+ ///
740
+ /// Not all tests can be re-executed since certain cheatcodes contain
741
+ /// non-deterministic side-effects.
742
+ OnFailure,
743
+ }
744
+
745
+ impl From<CollectStackTraces> for edr_solidity_tests::CollectStackTraces {
746
+ fn from(value: CollectStackTraces) -> Self {
747
+ match value {
748
+ CollectStackTraces::Always => edr_solidity_tests::CollectStackTraces::Always,
749
+ CollectStackTraces::OnFailure => edr_solidity_tests::CollectStackTraces::OnFailure,
750
+ }
751
+ }
752
+ }
753
+
724
754
  /// Configuration for [`SolidityTestRunnerConfigArgs::include_traces`] that
725
755
  /// controls execution trace decoding and inclusion in test results.
726
756
  #[napi]
@@ -42,7 +42,7 @@ pub struct ValueSnapshotEntry {
42
42
  pub value: String,
43
43
  }
44
44
 
45
- /// See [edr_solidity_tests::result::SuiteResult]
45
+ /// See [`edr_solidity_tests::result::SuiteResult`]
46
46
  #[napi]
47
47
  #[derive(Clone, Debug)]
48
48
  pub struct SuiteResult {
@@ -50,13 +50,13 @@ pub struct SuiteResult {
50
50
  /// callback
51
51
  #[napi(readonly)]
52
52
  pub id: ArtifactId,
53
- /// See [edr_solidity_tests::result::SuiteResult::duration]
53
+ /// See [`edr_solidity_tests::result::SuiteResult::duration`]
54
54
  #[napi(readonly)]
55
55
  pub duration_ns: BigInt,
56
- /// See [edr_solidity_tests::result::SuiteResult::test_results]
56
+ /// See [`edr_solidity_tests::result::SuiteResult::test_results`]
57
57
  #[napi(readonly)]
58
58
  pub test_results: Vec<TestResult>,
59
- /// See [edr_solidity_tests::result::SuiteResult::warnings]
59
+ /// See [`edr_solidity_tests::result::SuiteResult::warnings`]
60
60
  #[napi(readonly)]
61
61
  pub warnings: Vec<String>,
62
62
  }
@@ -80,29 +80,29 @@ impl SuiteResult {
80
80
  }
81
81
  }
82
82
 
83
- /// See [edr_solidity_tests::result::TestResult]
83
+ /// See [`edr_solidity_tests::result::TestResult`]
84
84
  #[napi]
85
85
  #[derive(Clone, Debug)]
86
86
  pub struct TestResult {
87
87
  /// The name of the test.
88
88
  #[napi(readonly)]
89
89
  pub name: String,
90
- /// See [edr_solidity_tests::result::TestResult::status]
90
+ /// See [`edr_solidity_tests::result::TestResult::status`]
91
91
  #[napi(readonly)]
92
92
  pub status: TestStatus,
93
- /// See [edr_solidity_tests::result::TestResult::reason]
93
+ /// See [`edr_solidity_tests::result::TestResult::reason`]
94
94
  #[napi(readonly)]
95
95
  pub reason: Option<String>,
96
- /// See [edr_solidity_tests::result::TestResult::counterexample]
96
+ /// See [`edr_solidity_tests::result::TestResult::counterexample`]
97
97
  #[napi(readonly)]
98
98
  pub counterexample: Option<Either<BaseCounterExample, CounterExampleSequence>>,
99
- /// See [edr_solidity_tests::result::TestResult::decoded_logs]
99
+ /// See [`edr_solidity_tests::result::TestResult::decoded_logs`]
100
100
  #[napi(readonly)]
101
101
  pub decoded_logs: Vec<String>,
102
- /// See [edr_solidity_tests::result::TestResult::kind]
102
+ /// See [`edr_solidity_tests::result::TestResult::kind`]
103
103
  #[napi(readonly)]
104
104
  pub kind: Either3<StandardTestKind, FuzzTestKind, InvariantTestKind>,
105
- /// See [edr_solidity_tests::result::TestResult::duration]
105
+ /// See [`edr_solidity_tests::result::TestResult::duration`]
106
106
  #[napi(readonly)]
107
107
  pub duration_ns: BigInt,
108
108
  /// Groups of value snapshot entries (incl. gas).
@@ -335,7 +335,7 @@ impl From<edr_solidity_tests::result::TestStatus> for TestStatus {
335
335
  }
336
336
  }
337
337
 
338
- /// See [edr_solidity_tests::result::TestKind::Standard]
338
+ /// See [`edr_solidity_tests::result::TestKind::Standard`]
339
339
  #[napi(object)]
340
340
  #[derive(Debug, Clone)]
341
341
  pub struct StandardTestKind {
@@ -344,22 +344,22 @@ pub struct StandardTestKind {
344
344
  pub consumed_gas: BigInt,
345
345
  }
346
346
 
347
- /// See [edr_solidity_tests::result::TestKind::Fuzz]
347
+ /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
348
348
  #[napi(object)]
349
349
  #[derive(Debug, Clone)]
350
350
  pub struct FuzzTestKind {
351
- /// See [edr_solidity_tests::result::TestKind::Fuzz]
351
+ /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
352
352
  #[napi(readonly)]
353
353
  pub runs: BigInt,
354
- /// See [edr_solidity_tests::result::TestKind::Fuzz]
354
+ /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
355
355
  #[napi(readonly)]
356
356
  pub mean_gas: BigInt,
357
- /// See [edr_solidity_tests::result::TestKind::Fuzz]
357
+ /// See [`edr_solidity_tests::result::TestKind::Fuzz`]
358
358
  #[napi(readonly)]
359
359
  pub median_gas: BigInt,
360
360
  }
361
361
 
362
- /// See [edr_solidity_tests::fuzz::FuzzCase]
362
+ /// See [`edr_solidity_tests::fuzz::FuzzCase`]
363
363
  #[napi(object)]
364
364
  #[derive(Clone)]
365
365
  pub struct FuzzCase {
@@ -383,17 +383,17 @@ impl Debug for FuzzCase {
383
383
  }
384
384
  }
385
385
 
386
- /// See [edr_solidity_tests::result::TestKind::Invariant]
386
+ /// See [`edr_solidity_tests::result::TestKind::Invariant`]
387
387
  #[napi(object)]
388
388
  #[derive(Debug, Clone)]
389
389
  pub struct InvariantTestKind {
390
- /// See [edr_solidity_tests::result::TestKind::Invariant]
390
+ /// See [`edr_solidity_tests::result::TestKind::Invariant`]
391
391
  #[napi(readonly)]
392
392
  pub runs: BigInt,
393
- /// See [edr_solidity_tests::result::TestKind::Invariant]
393
+ /// See [`edr_solidity_tests::result::TestKind::Invariant`]
394
394
  #[napi(readonly)]
395
395
  pub calls: BigInt,
396
- /// See [edr_solidity_tests::result::TestKind::Invariant]
396
+ /// See [`edr_solidity_tests::result::TestKind::Invariant`]
397
397
  #[napi(readonly)]
398
398
  pub reverts: BigInt,
399
399
  }
@@ -409,26 +409,26 @@ pub struct CounterExampleSequence {
409
409
  pub sequence: Vec<BaseCounterExample>,
410
410
  }
411
411
 
412
- /// See [edr_solidity_tests::fuzz::BaseCounterExample]
412
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample`]
413
413
  #[napi(object)]
414
414
  #[derive(Clone)]
415
415
  pub struct BaseCounterExample {
416
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::sender]
416
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::sender`]
417
417
  #[napi(readonly)]
418
418
  pub sender: Option<Uint8Array>,
419
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::addr]
419
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::addr`]
420
420
  #[napi(readonly)]
421
421
  pub address: Option<Uint8Array>,
422
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::calldata]
422
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::calldata`]
423
423
  #[napi(readonly)]
424
424
  pub calldata: Uint8Array,
425
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::contract_name]
425
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::contract_name`]
426
426
  #[napi(readonly)]
427
427
  pub contract_name: Option<String>,
428
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::signature]
428
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::signature`]
429
429
  #[napi(readonly)]
430
430
  pub signature: Option<String>,
431
- /// See [edr_solidity_tests::fuzz::BaseCounterExample::args]
431
+ /// See [`edr_solidity_tests::fuzz::BaseCounterExample::args`]
432
432
  #[napi(readonly)]
433
433
  pub args: Option<String>,
434
434
  }
@@ -604,7 +604,10 @@ impl CallTrace {
604
604
  loop {
605
605
  // We will break out of the loop before the stack goes empty.
606
606
  let mut item = stack.pop().unwrap();
607
- let node = &arena.nodes()[item.arena_index];
607
+ let node = arena
608
+ .nodes()
609
+ .get(item.arena_index)
610
+ .expect("Arena index should be valid");
608
611
 
609
612
  if item.visited {
610
613
  let mut logs = node
@@ -618,11 +621,20 @@ impl CallTrace {
618
621
  .iter()
619
622
  .filter_map(|ord| match *ord {
620
623
  traces::TraceMemberOrder::Log(i) => {
621
- let log = logs[i].take().unwrap();
624
+ let log = logs
625
+ .get_mut(i)
626
+ .expect("Log index should be valid")
627
+ .take()
628
+ .unwrap();
622
629
  Some(Either::B(log))
623
630
  }
624
631
  traces::TraceMemberOrder::Call(i) => {
625
- let child_trace = item.child_traces[i].take().unwrap();
632
+ let child_trace = item
633
+ .child_traces
634
+ .get_mut(i)
635
+ .expect("Child trace index should be valid")
636
+ .take()
637
+ .unwrap();
626
638
  Some(Either::A(child_trace))
627
639
  }
628
640
  traces::TraceMemberOrder::Step(_) => None,
@@ -632,7 +644,9 @@ impl CallTrace {
632
644
  let trace = CallTrace::new(node, children);
633
645
 
634
646
  if let Some(parent_stack_index) = item.parent_stack_index {
635
- let parent = &mut stack[parent_stack_index];
647
+ let parent = stack
648
+ .get_mut(parent_stack_index)
649
+ .expect("Parent stack index should be valid");
636
650
  parent.child_traces.push(Some(trace));
637
651
  } else {
638
652
  return trace;
@@ -46,7 +46,9 @@ fn print_stack_trace(trace: SolidityStackTrace) -> napi::Result<()> {
46
46
  })?;
47
47
 
48
48
  let mut value = serde_json::to_value(entry)?;
49
- value["message"] = decoded_error_msg.into();
49
+ if let Some(obj) = value.as_object_mut() {
50
+ obj.insert("message".to_string(), decoded_error_msg.into());
51
+ }
50
52
  Ok(value)
51
53
  }
52
54
  })
@@ -22,11 +22,9 @@ pub struct ReturnData {
22
22
  impl ReturnData {
23
23
  #[napi(catch_unwind, constructor)]
24
24
  pub fn new(value: Uint8Array) -> Self {
25
- let selector = if value.len() >= 4 {
26
- Some(value[0..4].try_into().unwrap())
27
- } else {
28
- None
29
- };
25
+ let selector = value
26
+ .get(0..4)
27
+ .map(|selector| selector.try_into().expect("selector is 4 bytes"));
30
28
 
31
29
  Self { value, selector }
32
30
  }