@nomicfoundation/edr 0.10.0 → 0.12.0-alpha.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.
package/src/cast.rs CHANGED
@@ -1,7 +1,7 @@
1
- use edr_eth::{Address, Bytes, B256, B64, U256};
1
+ use edr_eth::{Address, B64, B256, Bytecode, Bytes, U256};
2
2
  use napi::{
3
- bindgen_prelude::{BigInt, Buffer},
4
3
  Status,
4
+ bindgen_prelude::{BigInt, Buffer, Uint8Array},
5
5
  };
6
6
 
7
7
  /// An attempted conversion that consumes `self`, which may or may not be
@@ -29,6 +29,20 @@ impl TryCast<Address> for Buffer {
29
29
  }
30
30
  }
31
31
 
32
+ impl TryCast<Address> for Uint8Array {
33
+ type Error = napi::Error;
34
+
35
+ fn try_cast(self) -> std::result::Result<Address, Self::Error> {
36
+ if self.len() != 20 {
37
+ return Err(napi::Error::new(
38
+ Status::InvalidArg,
39
+ "Uint8Array was expected to be 20 bytes.".to_string(),
40
+ ));
41
+ }
42
+ Ok(Address::from_slice(&self))
43
+ }
44
+ }
45
+
32
46
  impl TryCast<B64> for Buffer {
33
47
  type Error = napi::Error;
34
48
 
@@ -57,6 +71,20 @@ impl TryCast<B256> for Buffer {
57
71
  }
58
72
  }
59
73
 
74
+ impl TryCast<Bytecode> for Uint8Array {
75
+ type Error = napi::Error;
76
+
77
+ fn try_cast(self) -> std::result::Result<Bytecode, Self::Error> {
78
+ let bytes = Bytes::copy_from_slice(&self);
79
+ Bytecode::new_raw_checked(bytes).map_err(|error| {
80
+ napi::Error::new(
81
+ Status::InvalidArg,
82
+ format!("Uint8Array was not valid bytecode: {error}"),
83
+ )
84
+ })
85
+ }
86
+ }
87
+
60
88
  impl TryCast<u64> for BigInt {
61
89
  type Error = napi::Error;
62
90
 
@@ -81,6 +109,30 @@ impl TryCast<u64> for BigInt {
81
109
  }
82
110
  }
83
111
 
112
+ impl TryCast<u128> for BigInt {
113
+ type Error = napi::Error;
114
+
115
+ fn try_cast(self) -> std::result::Result<u128, Self::Error> {
116
+ let (signed, value, lossless) = self.get_u128();
117
+
118
+ if signed {
119
+ return Err(napi::Error::new(
120
+ Status::InvalidArg,
121
+ "BigInt was expected to be unsigned.".to_string(),
122
+ ));
123
+ }
124
+
125
+ if !lossless {
126
+ return Err(napi::Error::new(
127
+ Status::InvalidArg,
128
+ "BigInt was expected to fit within 128 bits.".to_string(),
129
+ ));
130
+ }
131
+
132
+ Ok(value)
133
+ }
134
+ }
135
+
84
136
  impl TryCast<usize> for BigInt {
85
137
  type Error = napi::Error;
86
138
 
@@ -0,0 +1,51 @@
1
+ use std::sync::Arc;
2
+
3
+ use edr_eth::l1;
4
+ use edr_generic::GenericChainSpec;
5
+ use edr_napi_core::{
6
+ logger::{self, Logger},
7
+ provider::{self, ProviderBuilder, SyncProviderFactory},
8
+ spec::SyncNapiSpec as _,
9
+ subscription,
10
+ };
11
+ use edr_solidity::contract_decoder::ContractDecoder;
12
+ use napi_derive::napi;
13
+
14
+ use crate::provider::ProviderFactory;
15
+
16
+ pub struct GenericChainProviderFactory;
17
+
18
+ impl SyncProviderFactory for GenericChainProviderFactory {
19
+ fn create_provider_builder(
20
+ &self,
21
+ env: &napi::Env,
22
+ provider_config: edr_napi_core::provider::Config,
23
+ logger_config: logger::Config,
24
+ subscription_config: subscription::Config,
25
+ contract_decoder: Arc<ContractDecoder>,
26
+ ) -> napi::Result<Box<dyn provider::Builder>> {
27
+ let logger = Logger::<GenericChainSpec>::new(logger_config, Arc::clone(&contract_decoder))?;
28
+
29
+ let provider_config =
30
+ edr_provider::ProviderConfig::<l1::SpecId>::try_from(provider_config)?;
31
+
32
+ let subscription_callback =
33
+ subscription::Callback::new(env, subscription_config.subscription_callback)?;
34
+
35
+ Ok(Box::new(ProviderBuilder::new(
36
+ contract_decoder,
37
+ Box::new(logger),
38
+ provider_config,
39
+ subscription_callback,
40
+ )))
41
+ }
42
+ }
43
+
44
+ #[napi]
45
+ pub const GENERIC_CHAIN_TYPE: &str = GenericChainSpec::CHAIN_TYPE;
46
+
47
+ #[napi]
48
+ pub fn generic_chain_provider_factory() -> ProviderFactory {
49
+ let factory: Arc<dyn SyncProviderFactory> = Arc::new(GenericChainProviderFactory);
50
+ factory.into()
51
+ }
@@ -0,0 +1,260 @@
1
+ use std::{str::FromStr, sync::Arc};
2
+
3
+ use edr_eth::l1::{self, L1ChainSpec};
4
+ use edr_evm::eips::{
5
+ eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_UNSUPPORTED_BYTECODE},
6
+ eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_BYTECODE},
7
+ };
8
+ use edr_napi_core::{
9
+ logger::Logger,
10
+ provider::{self, ProviderBuilder, SyncProviderFactory},
11
+ spec::SyncNapiSpec as _,
12
+ subscription,
13
+ };
14
+ use edr_solidity::contract_decoder::ContractDecoder;
15
+ use napi::bindgen_prelude::{BigInt, Uint8Array};
16
+ use napi_derive::napi;
17
+
18
+ use crate::{account::Account, provider::ProviderFactory};
19
+
20
+ pub struct L1ProviderFactory;
21
+
22
+ impl SyncProviderFactory for L1ProviderFactory {
23
+ fn create_provider_builder(
24
+ &self,
25
+ env: &napi::Env,
26
+ provider_config: edr_napi_core::provider::Config,
27
+ logger_config: edr_napi_core::logger::Config,
28
+ subscription_config: edr_napi_core::subscription::Config,
29
+ contract_decoder: Arc<ContractDecoder>,
30
+ ) -> napi::Result<Box<dyn provider::Builder>> {
31
+ let logger = Logger::<L1ChainSpec>::new(logger_config, Arc::clone(&contract_decoder))?;
32
+
33
+ let provider_config =
34
+ edr_provider::ProviderConfig::<l1::SpecId>::try_from(provider_config)?;
35
+
36
+ let subscription_callback =
37
+ subscription::Callback::new(env, subscription_config.subscription_callback)?;
38
+
39
+ Ok(Box::new(ProviderBuilder::new(
40
+ contract_decoder,
41
+ Box::new(logger),
42
+ provider_config,
43
+ subscription_callback,
44
+ )))
45
+ }
46
+ }
47
+
48
+ #[napi]
49
+ pub const L1_CHAIN_TYPE: &str = L1ChainSpec::CHAIN_TYPE;
50
+
51
+ #[napi]
52
+ pub fn l1_genesis_state(hardfork: SpecId) -> Vec<Account> {
53
+ // Use closures for lazy execution
54
+ let beacon_roots_account_constructor = || Account {
55
+ address: Uint8Array::from(BEACON_ROOTS_ADDRESS.as_slice()),
56
+ balance: BigInt::from(0u64),
57
+ nonce: BigInt::from(0u64),
58
+ code: Some(Uint8Array::from(BEACON_ROOTS_BYTECODE)),
59
+ storage: Vec::new(),
60
+ };
61
+
62
+ let history_storage_account_constructor = || Account {
63
+ address: Uint8Array::from(HISTORY_STORAGE_ADDRESS.as_slice()),
64
+ balance: BigInt::from(0u64),
65
+ nonce: BigInt::from(0u64),
66
+ code: Some(Uint8Array::from(HISTORY_STORAGE_UNSUPPORTED_BYTECODE)),
67
+ storage: Vec::new(),
68
+ };
69
+
70
+ if hardfork < SpecId::Cancun {
71
+ Vec::new()
72
+ } else if hardfork < SpecId::Prague {
73
+ vec![beacon_roots_account_constructor()]
74
+ } else {
75
+ vec![
76
+ beacon_roots_account_constructor(),
77
+ history_storage_account_constructor(),
78
+ ]
79
+ }
80
+ }
81
+
82
+ #[napi]
83
+ pub fn l1_provider_factory() -> ProviderFactory {
84
+ let factory: Arc<dyn SyncProviderFactory> = Arc::new(L1ProviderFactory);
85
+ factory.into()
86
+ }
87
+
88
+ /// Identifier for the Ethereum spec.
89
+ #[napi]
90
+ #[derive(PartialEq, Eq, PartialOrd, Ord)]
91
+ pub enum SpecId {
92
+ /// Frontier
93
+ Frontier = 0,
94
+ /// Frontier Thawing
95
+ FrontierThawing = 1,
96
+ /// Homestead
97
+ Homestead = 2,
98
+ /// DAO Fork
99
+ DaoFork = 3,
100
+ /// Tangerine
101
+ Tangerine = 4,
102
+ /// Spurious Dragon
103
+ SpuriousDragon = 5,
104
+ /// Byzantium
105
+ Byzantium = 6,
106
+ /// Constantinople
107
+ Constantinople = 7,
108
+ /// Petersburg
109
+ Petersburg = 8,
110
+ /// Istanbul
111
+ Istanbul = 9,
112
+ /// Muir Glacier
113
+ MuirGlacier = 10,
114
+ /// Berlin
115
+ Berlin = 11,
116
+ /// London
117
+ London = 12,
118
+ /// Arrow Glacier
119
+ ArrowGlacier = 13,
120
+ /// Gray Glacier
121
+ GrayGlacier = 14,
122
+ /// Merge
123
+ Merge = 15,
124
+ /// Shanghai
125
+ Shanghai = 16,
126
+ /// Cancun
127
+ Cancun = 17,
128
+ /// Prague
129
+ Prague = 18,
130
+ }
131
+
132
+ impl FromStr for SpecId {
133
+ type Err = napi::Error;
134
+
135
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
136
+ match s {
137
+ edr_eth::l1::hardfork::name::FRONTIER => Ok(SpecId::Frontier),
138
+ edr_eth::l1::hardfork::name::FRONTIER_THAWING => Ok(SpecId::FrontierThawing),
139
+ edr_eth::l1::hardfork::name::HOMESTEAD => Ok(SpecId::Homestead),
140
+ edr_eth::l1::hardfork::name::DAO_FORK => Ok(SpecId::DaoFork),
141
+ edr_eth::l1::hardfork::name::TANGERINE => Ok(SpecId::Tangerine),
142
+ edr_eth::l1::hardfork::name::SPURIOUS_DRAGON => Ok(SpecId::SpuriousDragon),
143
+ edr_eth::l1::hardfork::name::BYZANTIUM => Ok(SpecId::Byzantium),
144
+ edr_eth::l1::hardfork::name::CONSTANTINOPLE => Ok(SpecId::Constantinople),
145
+ edr_eth::l1::hardfork::name::PETERSBURG => Ok(SpecId::Petersburg),
146
+ edr_eth::l1::hardfork::name::ISTANBUL => Ok(SpecId::Istanbul),
147
+ edr_eth::l1::hardfork::name::MUIR_GLACIER => Ok(SpecId::MuirGlacier),
148
+ edr_eth::l1::hardfork::name::BERLIN => Ok(SpecId::Berlin),
149
+ edr_eth::l1::hardfork::name::LONDON => Ok(SpecId::London),
150
+ edr_eth::l1::hardfork::name::ARROW_GLACIER => Ok(SpecId::ArrowGlacier),
151
+ edr_eth::l1::hardfork::name::GRAY_GLACIER => Ok(SpecId::GrayGlacier),
152
+ edr_eth::l1::hardfork::name::MERGE => Ok(SpecId::Merge),
153
+ edr_eth::l1::hardfork::name::SHANGHAI => Ok(SpecId::Shanghai),
154
+ edr_eth::l1::hardfork::name::CANCUN => Ok(SpecId::Cancun),
155
+ edr_eth::l1::hardfork::name::PRAGUE => Ok(SpecId::Prague),
156
+ _ => Err(napi::Error::new(
157
+ napi::Status::InvalidArg,
158
+ format!("The provided hardfork `{s}` is not supported."),
159
+ )),
160
+ }
161
+ }
162
+ }
163
+
164
+ impl From<SpecId> for edr_eth::l1::SpecId {
165
+ fn from(value: SpecId) -> Self {
166
+ match value {
167
+ SpecId::Frontier => edr_eth::l1::SpecId::FRONTIER,
168
+ SpecId::FrontierThawing => edr_eth::l1::SpecId::FRONTIER_THAWING,
169
+ SpecId::Homestead => edr_eth::l1::SpecId::HOMESTEAD,
170
+ SpecId::DaoFork => edr_eth::l1::SpecId::DAO_FORK,
171
+ SpecId::Tangerine => edr_eth::l1::SpecId::TANGERINE,
172
+ SpecId::SpuriousDragon => edr_eth::l1::SpecId::SPURIOUS_DRAGON,
173
+ SpecId::Byzantium => edr_eth::l1::SpecId::BYZANTIUM,
174
+ SpecId::Constantinople => edr_eth::l1::SpecId::CONSTANTINOPLE,
175
+ SpecId::Petersburg => edr_eth::l1::SpecId::PETERSBURG,
176
+ SpecId::Istanbul => edr_eth::l1::SpecId::ISTANBUL,
177
+ SpecId::MuirGlacier => edr_eth::l1::SpecId::MUIR_GLACIER,
178
+ SpecId::Berlin => edr_eth::l1::SpecId::BERLIN,
179
+ SpecId::London => edr_eth::l1::SpecId::LONDON,
180
+ SpecId::ArrowGlacier => edr_eth::l1::SpecId::ARROW_GLACIER,
181
+ SpecId::GrayGlacier => edr_eth::l1::SpecId::GRAY_GLACIER,
182
+ SpecId::Merge => edr_eth::l1::SpecId::MERGE,
183
+ SpecId::Shanghai => edr_eth::l1::SpecId::SHANGHAI,
184
+ SpecId::Cancun => edr_eth::l1::SpecId::CANCUN,
185
+ SpecId::Prague => edr_eth::l1::SpecId::PRAGUE,
186
+ }
187
+ }
188
+ }
189
+
190
+ /// Tries to parse the provided string to create a [`SpecId`] instance.
191
+ ///
192
+ /// Returns an error if the string does not match any known hardfork.
193
+ #[napi]
194
+ pub fn l1_hardfork_from_string(hardfork: String) -> napi::Result<SpecId> {
195
+ hardfork.parse()
196
+ }
197
+
198
+ #[napi]
199
+ pub fn l1_hardfork_to_string(harfork: SpecId) -> &'static str {
200
+ match harfork {
201
+ SpecId::Frontier => edr_eth::l1::hardfork::name::FRONTIER,
202
+ SpecId::FrontierThawing => edr_eth::l1::hardfork::name::FRONTIER_THAWING,
203
+ SpecId::Homestead => edr_eth::l1::hardfork::name::HOMESTEAD,
204
+ SpecId::DaoFork => edr_eth::l1::hardfork::name::DAO_FORK,
205
+ SpecId::Tangerine => edr_eth::l1::hardfork::name::TANGERINE,
206
+ SpecId::SpuriousDragon => edr_eth::l1::hardfork::name::SPURIOUS_DRAGON,
207
+ SpecId::Byzantium => edr_eth::l1::hardfork::name::BYZANTIUM,
208
+ SpecId::Constantinople => edr_eth::l1::hardfork::name::CONSTANTINOPLE,
209
+ SpecId::Petersburg => edr_eth::l1::hardfork::name::PETERSBURG,
210
+ SpecId::Istanbul => edr_eth::l1::hardfork::name::ISTANBUL,
211
+ SpecId::MuirGlacier => edr_eth::l1::hardfork::name::MUIR_GLACIER,
212
+ SpecId::Berlin => edr_eth::l1::hardfork::name::BERLIN,
213
+ SpecId::London => edr_eth::l1::hardfork::name::LONDON,
214
+ SpecId::ArrowGlacier => edr_eth::l1::hardfork::name::ARROW_GLACIER,
215
+ SpecId::GrayGlacier => edr_eth::l1::hardfork::name::GRAY_GLACIER,
216
+ SpecId::Merge => edr_eth::l1::hardfork::name::MERGE,
217
+ SpecId::Shanghai => edr_eth::l1::hardfork::name::SHANGHAI,
218
+ SpecId::Cancun => edr_eth::l1::hardfork::name::CANCUN,
219
+ SpecId::Prague => edr_eth::l1::hardfork::name::PRAGUE,
220
+ }
221
+ }
222
+
223
+ /// Returns the latest supported OP hardfork.
224
+ ///
225
+ /// The returned value will be updated after each network upgrade.
226
+ #[napi]
227
+ pub fn l1_hardfork_latest() -> SpecId {
228
+ SpecId::Prague
229
+ }
230
+
231
+ macro_rules! export_spec_id {
232
+ ($($variant:ident),*) => {
233
+ $(
234
+ #[napi]
235
+ pub const $variant: &str = edr_eth::l1::hardfork::name::$variant;
236
+ )*
237
+ };
238
+ }
239
+
240
+ export_spec_id!(
241
+ FRONTIER,
242
+ FRONTIER_THAWING,
243
+ HOMESTEAD,
244
+ DAO_FORK,
245
+ TANGERINE,
246
+ SPURIOUS_DRAGON,
247
+ BYZANTIUM,
248
+ CONSTANTINOPLE,
249
+ PETERSBURG,
250
+ ISTANBUL,
251
+ MUIR_GLACIER,
252
+ BERLIN,
253
+ LONDON,
254
+ ARROW_GLACIER,
255
+ GRAY_GLACIER,
256
+ MERGE,
257
+ SHANGHAI,
258
+ CANCUN,
259
+ PRAGUE
260
+ );