@mainsail/evm 0.0.1-evm.52 → 0.0.1-evm.53

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.
@@ -0,0 +1,110 @@
1
+ use mainsail_evm_core::logger::{LogLevel, Logger};
2
+ use napi::bindgen_prelude::*;
3
+ use napi::threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunctionCallMode};
4
+ use napi_derive::napi;
5
+ use std::sync::mpsc::{Receiver, Sender, channel};
6
+ use std::thread::{self, JoinHandle};
7
+
8
+ #[napi(js_name = "LogLevel")]
9
+ pub enum JsLogLevel {
10
+ Info,
11
+ Debug,
12
+ Notice,
13
+ Alert,
14
+ Warn,
15
+ }
16
+
17
+ impl From<LogLevel> for JsLogLevel {
18
+ fn from(value: LogLevel) -> Self {
19
+ match value {
20
+ LogLevel::Info => Self::Info,
21
+ LogLevel::Debug => Self::Debug,
22
+ LogLevel::Notice => Self::Notice,
23
+ LogLevel::Alert => Self::Alert,
24
+ LogLevel::Warn => Self::Warn,
25
+ }
26
+ }
27
+ }
28
+
29
+ #[napi(object)]
30
+ pub struct JsLogMessage {
31
+ pub level: JsLogLevel,
32
+ pub message: String,
33
+ }
34
+
35
+ pub struct JsLogger {
36
+ internal_logger: Logger,
37
+ logger_handle: Option<JoinHandle<()>>,
38
+ }
39
+
40
+ impl JsLogger {
41
+ const DROP_MESSAGE: &'static str = "DROP";
42
+
43
+ pub fn new(logger_callback: Option<Function<'static, JsLogMessage, ()>>) -> Result<Self> {
44
+ let mut logger_sender: Option<Sender<(LogLevel, String)>> = None;
45
+ let mut logger_handle: Option<JoinHandle<()>> = None;
46
+
47
+ if let Some(logger_callback) = logger_callback {
48
+ let (sender, receiver): (Sender<(LogLevel, String)>, Receiver<(LogLevel, String)>) =
49
+ channel();
50
+
51
+ let tsfn = logger_callback.build_threadsafe_function().build_callback(
52
+ |ctx: ThreadsafeCallContext<JsLogMessage>| -> Result<JsLogMessage> {
53
+ Ok(ctx.value)
54
+ },
55
+ )?;
56
+
57
+ // Spawn a thread to listen for log messages and invoke the JS callback
58
+ let handle = thread::spawn({
59
+ // let tsfn = tsfn.clone();
60
+ move || {
61
+ for (level, message) in receiver {
62
+ if level == LogLevel::Notice && message == Self::DROP_MESSAGE {
63
+ break;
64
+ }
65
+
66
+ tsfn.call(
67
+ JsLogMessage {
68
+ level: level.into(),
69
+ message,
70
+ },
71
+ ThreadsafeFunctionCallMode::NonBlocking,
72
+ );
73
+ }
74
+
75
+ ()
76
+ }
77
+ });
78
+
79
+ logger_sender.replace(sender.clone());
80
+ logger_handle.replace(handle);
81
+ }
82
+
83
+ let internal_logger = Logger::new(logger_sender);
84
+
85
+ Ok(Self {
86
+ internal_logger,
87
+ logger_handle,
88
+ })
89
+ }
90
+
91
+ pub fn inner(&self) -> Logger {
92
+ self.internal_logger.clone()
93
+ }
94
+
95
+ pub fn log(&self, level: LogLevel, message: String) {
96
+ self.internal_logger.log(level, message);
97
+ }
98
+ }
99
+
100
+ impl Drop for JsLogger {
101
+ fn drop(&mut self) {
102
+ if let Some(handle) = self.logger_handle.take() {
103
+ if let Some(sender) = self.internal_logger.sender.as_ref() {
104
+ let _ = sender.send((LogLevel::Notice, Self::DROP_MESSAGE.into()));
105
+ }
106
+
107
+ handle.join().expect("failed to join logger thread");
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,542 @@
1
+ use mainsail_evm_core::{
2
+ account::AccountInfoExtended,
3
+ db::{BlockHeaderData, ProofData, TransactionData},
4
+ legacy::{LegacyAccountAttributes, LegacyColdWallet, LegacyMultiSignatureAttribute},
5
+ receipt::TxReceipt,
6
+ state_changes::AccountUpdate,
7
+ };
8
+ use napi::bindgen_prelude::{BigInt, Buffer};
9
+ use napi_derive::napi;
10
+ use revm::{
11
+ primitives::{B256, Bytes, hex::ToHexExt},
12
+ state::AccountInfo,
13
+ };
14
+
15
+ use crate::{
16
+ ctx::{JsBlockHeaderData, JsCommitData, JsProofData, JsTransactionData},
17
+ utils,
18
+ };
19
+
20
+ #[napi(object)]
21
+ pub struct JsProcessResult {
22
+ pub receipt: JsTransactionReceipt,
23
+ }
24
+ impl JsProcessResult {
25
+ pub fn new(receipt: TxReceipt) -> Self {
26
+ Self {
27
+ receipt: JsTransactionReceipt::new(receipt),
28
+ }
29
+ }
30
+ }
31
+
32
+ #[napi(object)]
33
+ pub struct JsSimulateResult {
34
+ pub receipt: JsTransactionReceipt,
35
+ }
36
+ impl JsSimulateResult {
37
+ pub fn new(receipt: TxReceipt) -> Self {
38
+ Self {
39
+ receipt: JsTransactionReceipt::new(receipt),
40
+ }
41
+ }
42
+ }
43
+
44
+ #[napi(object, object_from_js = false)]
45
+ pub struct JsCommitResult {
46
+ pub dirty_accounts: Vec<JsAccountUpdate>,
47
+ }
48
+
49
+ impl JsCommitResult {
50
+ pub fn new(result: CommitResult) -> anyhow::Result<Self> {
51
+ let mut dirty_accounts = Vec::with_capacity(result.dirty_accounts.len());
52
+ for item in result.dirty_accounts {
53
+ dirty_accounts.push(JsAccountUpdate::new(item));
54
+ }
55
+
56
+ Ok(Self { dirty_accounts })
57
+ }
58
+ }
59
+
60
+ #[napi(object)]
61
+ pub struct JsViewResult {
62
+ pub success: bool,
63
+ pub output: Option<Buffer>,
64
+ }
65
+ impl JsViewResult {
66
+ pub fn new(result: TxViewResult) -> anyhow::Result<Self> {
67
+ Ok(Self {
68
+ success: result.success,
69
+ output: result.output.map(|o| utils::convert_bytes_to_js_buffer(o)),
70
+ })
71
+ }
72
+ }
73
+
74
+ #[napi(object)]
75
+ pub struct JsPreverifyTransactionResult {
76
+ pub success: bool,
77
+ pub initial_gas_used: BigInt,
78
+ pub error: Option<String>,
79
+ }
80
+
81
+ impl JsPreverifyTransactionResult {
82
+ pub fn new(result: PreverifyTxResult) -> Self {
83
+ Self {
84
+ success: result.success,
85
+ initial_gas_used: result.initial_gas_used.into(),
86
+ error: result.error,
87
+ }
88
+ }
89
+ }
90
+
91
+ #[napi(object)]
92
+ pub struct JsTransactionReceipt {
93
+ pub block_number: Option<BigInt>,
94
+ pub tx_hash: Option<String>,
95
+
96
+ pub gas_used: BigInt,
97
+ pub cumulative_gas_used: BigInt,
98
+ pub gas_refunded: BigInt,
99
+ pub status: u8,
100
+ pub contract_address: Option<String>,
101
+
102
+ pub logs: serde_json::Value,
103
+ pub output: Option<Buffer>,
104
+ }
105
+
106
+ #[derive(Default)]
107
+ pub struct CommitResult {
108
+ pub dirty_accounts: Vec<AccountUpdate>,
109
+ }
110
+
111
+ pub struct TxViewResult {
112
+ pub success: bool,
113
+ pub output: Option<Bytes>,
114
+ }
115
+
116
+ #[derive(Default)]
117
+ pub struct PreverifyTxResult {
118
+ pub success: bool,
119
+ pub initial_gas_used: u64,
120
+ pub error: Option<String>,
121
+ }
122
+
123
+ impl JsTransactionReceipt {
124
+ pub fn new(receipt: TxReceipt) -> Self {
125
+ JsTransactionReceipt {
126
+ gas_used: receipt.gas_used.into(),
127
+ cumulative_gas_used: receipt.cumulative_gas_used.into(),
128
+ gas_refunded: receipt.gas_refunded.into(),
129
+ status: receipt.success as u8,
130
+ contract_address: receipt.contract_address,
131
+ logs: receipt
132
+ .logs
133
+ .map(|l| serde_json::to_value(l).unwrap())
134
+ .unwrap_or_else(|| serde_json::Value::Null), // TODO: check if null is correct
135
+ output: receipt.output.map(|o| utils::convert_bytes_to_js_buffer(o)),
136
+ block_number: None,
137
+ tx_hash: None,
138
+ }
139
+ }
140
+ }
141
+
142
+ impl JsCommitData {
143
+ pub fn new(
144
+ proof: ProofData,
145
+ header: BlockHeaderData,
146
+ transactions: Vec<TransactionData>,
147
+ ) -> Self {
148
+ JsCommitData {
149
+ proof: JsProofData::new(proof),
150
+ header: JsBlockHeaderData::new(header),
151
+ transactions: transactions
152
+ .into_iter()
153
+ .map(|tx| JsTransactionData::new(tx))
154
+ .collect(),
155
+ }
156
+ }
157
+ }
158
+
159
+ impl JsProofData {
160
+ pub fn new(proof: ProofData) -> Self {
161
+ JsProofData {
162
+ round: proof.round,
163
+ signature: proof.signature.encode_hex(),
164
+ validator_set: proof.validator_set.into(),
165
+ }
166
+ }
167
+ }
168
+
169
+ impl JsBlockHeaderData {
170
+ pub fn new(header: BlockHeaderData) -> Self {
171
+ JsBlockHeaderData {
172
+ version: header.version,
173
+ timestamp: header.timestamp.into(),
174
+ number: header.number,
175
+ round: header.round,
176
+ hash: format!("{:x}", header.hash),
177
+ parent_hash: format!("{:x}", header.parent_hash),
178
+ state_root: format!("{:x}", header.state_root),
179
+ logs_bloom: header.logs_bloom.encode_hex(),
180
+ transactions_root: format!("{:x}", header.transactions_root),
181
+ transactions_count: header.transactions_count,
182
+ gas_used: header.gas_used,
183
+ fee: utils::convert_u256_to_bigint(header.fee),
184
+ reward: utils::convert_u256_to_bigint(header.reward),
185
+ payload_size: header.payload_size,
186
+ proposer: header.proposer.to_string(),
187
+ }
188
+ }
189
+ }
190
+
191
+ impl JsTransactionData {
192
+ pub fn new(tx: TransactionData) -> Self {
193
+ JsTransactionData {
194
+ block_number: tx.block_number,
195
+ tx_hash: format!("{:x}", tx.tx_hash),
196
+ from: tx.from.to_string(),
197
+ sender_public_key: tx.sender_public_key,
198
+ legacy_address: tx.legacy_address.map(|address| address.to_string()),
199
+ to: tx.to.map(|address| address.to_string()),
200
+ gas_limit: tx.gas_limit.into(),
201
+ gas_price: tx.gas_price.into(),
202
+ value: utils::convert_u256_to_bigint(tx.value),
203
+ nonce: tx.nonce.into(),
204
+ data: utils::convert_bytes_to_js_buffer(tx.data),
205
+ v: tx.v,
206
+ r: utils::convert_u256_to_hex(tx.r),
207
+ s: utils::convert_u256_to_hex(tx.s),
208
+ legacy_second_signature: tx.legacy_second_signature,
209
+ index: tx.index,
210
+ }
211
+ }
212
+ }
213
+
214
+ #[napi(object)]
215
+ pub struct JsAccountInfo {
216
+ pub balance: BigInt,
217
+ pub nonce: BigInt,
218
+ }
219
+
220
+ impl JsAccountInfo {
221
+ pub fn new(account_info: AccountInfo) -> anyhow::Result<Self> {
222
+ Ok(JsAccountInfo {
223
+ nonce: account_info.nonce.into(),
224
+ balance: utils::convert_u256_to_bigint(account_info.balance),
225
+ })
226
+ }
227
+ }
228
+
229
+ impl TryInto<AccountInfo> for JsAccountInfo {
230
+ type Error = anyhow::Error;
231
+
232
+ fn try_into(self) -> Result<AccountInfo, Self::Error> {
233
+ Ok(AccountInfo {
234
+ balance: utils::convert_bigint_to_u256(self.balance)?,
235
+ nonce: self.nonce.get_u64().1,
236
+ ..Default::default()
237
+ })
238
+ }
239
+ }
240
+
241
+ #[napi(object)]
242
+ pub struct JsAccountUpdate {
243
+ pub address: String,
244
+ pub balance: BigInt,
245
+ pub nonce: BigInt,
246
+ pub vote: Option<String>,
247
+ pub unvote: Option<String>,
248
+ pub username: Option<String>,
249
+ pub username_resigned: bool,
250
+ pub legacy_merge_info: Option<JsAccountMergeInfo>,
251
+ }
252
+
253
+ impl JsAccountUpdate {
254
+ pub fn new(account_update: AccountUpdate) -> Self {
255
+ let vote = account_update.vote.map(|vote| vote.to_string());
256
+ let unvote = account_update.unvote.map(|unvote| unvote.to_string());
257
+ let username = account_update.username.map(|username| username.to_string());
258
+
259
+ let legacy_merge_info = match &account_update.merge_info {
260
+ Some(legacy_merge_info) => Some(JsAccountMergeInfo {
261
+ address: legacy_merge_info.legacy_address.to_string(),
262
+ tx_hash: legacy_merge_info.transaction_hash.to_string(),
263
+ }),
264
+ None => None,
265
+ };
266
+
267
+ JsAccountUpdate {
268
+ address: account_update.address.to_checksum(None),
269
+ nonce: account_update.nonce.into(),
270
+ balance: utils::convert_u256_to_bigint(account_update.balance),
271
+ vote,
272
+ unvote,
273
+ username,
274
+ username_resigned: account_update.username_resigned,
275
+ legacy_merge_info,
276
+ }
277
+ }
278
+ }
279
+
280
+ #[napi(object)]
281
+ pub struct JsAccountInfoExtended {
282
+ pub address: String,
283
+ pub balance: BigInt,
284
+ pub nonce: BigInt,
285
+ pub legacy_attributes: JsLegacyAttributes,
286
+ }
287
+
288
+ #[napi(object)]
289
+ pub struct JsLegacyColdWallet {
290
+ pub address: String,
291
+ pub balance: BigInt,
292
+ pub legacy_attributes: JsLegacyAttributes,
293
+ pub merge_info: Option<JsAccountMergeInfo>,
294
+ }
295
+
296
+ #[napi(object)]
297
+ pub struct JsAccountMergeInfo {
298
+ pub address: String,
299
+ pub tx_hash: String,
300
+ }
301
+
302
+ impl JsLegacyColdWallet {
303
+ pub fn new(wallet: LegacyColdWallet) -> Self {
304
+ let merge_info = if let Some(merged_account) = wallet.merge_info {
305
+ Some(JsAccountMergeInfo {
306
+ address: merged_account.1.to_string(),
307
+ tx_hash: merged_account.0.to_string(),
308
+ })
309
+ } else {
310
+ None
311
+ };
312
+
313
+ JsLegacyColdWallet {
314
+ address: wallet.address.to_string(),
315
+ balance: utils::convert_u256_to_bigint(wallet.balance),
316
+ legacy_attributes: JsLegacyAttributes::new(wallet.legacy_attributes),
317
+ merge_info,
318
+ }
319
+ }
320
+ }
321
+
322
+ #[napi(object)]
323
+ pub struct JsLegacyAttributes {
324
+ pub legacy_nonce: Option<BigInt>,
325
+ pub second_public_key: Option<String>,
326
+ pub multi_signature: Option<JsLegacyMultiSignatureAttribute>,
327
+ }
328
+
329
+ #[napi(object)]
330
+ pub struct JsLegacyMultiSignatureAttribute {
331
+ pub min: u32,
332
+ pub public_keys: Vec<String>,
333
+ }
334
+
335
+ impl JsAccountInfoExtended {
336
+ pub fn new(account_info_extended: AccountInfoExtended) -> Self {
337
+ JsAccountInfoExtended {
338
+ address: account_info_extended.address.to_string(),
339
+ nonce: account_info_extended.info.nonce.into(),
340
+ balance: utils::convert_u256_to_bigint(account_info_extended.info.balance),
341
+ legacy_attributes: JsLegacyAttributes::new(account_info_extended.legacy_attributes),
342
+ }
343
+ }
344
+ }
345
+
346
+ impl TryInto<AccountInfoExtended> for JsAccountInfoExtended {
347
+ type Error = crate::Error;
348
+
349
+ fn try_into(self) -> Result<AccountInfoExtended, Self::Error> {
350
+ Ok(AccountInfoExtended {
351
+ address: utils::create_address_from_string(&self.address)?,
352
+ info: AccountInfo {
353
+ balance: utils::convert_bigint_to_u256(self.balance)?,
354
+ nonce: self.nonce.get_u64().1,
355
+ ..Default::default()
356
+ },
357
+ legacy_attributes: self.legacy_attributes.try_into()?,
358
+ })
359
+ }
360
+ }
361
+
362
+ impl TryInto<LegacyColdWallet> for JsLegacyColdWallet {
363
+ type Error = crate::Error;
364
+
365
+ fn try_into(self) -> Result<LegacyColdWallet, Self::Error> {
366
+ let merge_info = if let Some(merge_info) = self.merge_info {
367
+ Some((
368
+ utils::convert_string_to_b256(merge_info.tx_hash)?,
369
+ utils::create_address_from_string(&merge_info.address)?,
370
+ ))
371
+ } else {
372
+ None
373
+ };
374
+
375
+ Ok(LegacyColdWallet {
376
+ address: utils::create_legacy_address_from_string(&self.address)?,
377
+ balance: utils::convert_bigint_to_u256(self.balance)?,
378
+ legacy_attributes: self.legacy_attributes.try_into()?,
379
+ merge_info,
380
+ })
381
+ }
382
+ }
383
+
384
+ impl JsLegacyAttributes {
385
+ pub fn new(legacy_attributes: LegacyAccountAttributes) -> Self {
386
+ let multi_signature = if let Some(multi_signature) = legacy_attributes.multi_signature {
387
+ Some(JsLegacyMultiSignatureAttribute {
388
+ min: multi_signature.min as u32,
389
+ public_keys: multi_signature.public_keys,
390
+ })
391
+ } else {
392
+ None
393
+ };
394
+
395
+ JsLegacyAttributes {
396
+ legacy_nonce: legacy_attributes.legacy_nonce.map(|nonce| nonce.into()),
397
+ second_public_key: legacy_attributes.second_public_key,
398
+ multi_signature,
399
+ }
400
+ }
401
+ }
402
+
403
+ impl Into<LegacyAccountAttributes> for JsLegacyAttributes {
404
+ fn into(self) -> LegacyAccountAttributes {
405
+ LegacyAccountAttributes {
406
+ legacy_nonce: self.legacy_nonce.map(|nonce| nonce.get_u64().1),
407
+ second_public_key: self.second_public_key,
408
+ multi_signature: self.multi_signature.map(Into::into),
409
+ }
410
+ }
411
+ }
412
+
413
+ impl Into<LegacyMultiSignatureAttribute> for JsLegacyMultiSignatureAttribute {
414
+ fn into(self) -> LegacyMultiSignatureAttribute {
415
+ LegacyMultiSignatureAttribute {
416
+ min: self.min as usize,
417
+ public_keys: self.public_keys,
418
+ }
419
+ }
420
+ }
421
+
422
+ #[napi(object)]
423
+ pub struct JsGetAccounts {
424
+ pub next_offset: Option<BigInt>,
425
+ pub accounts: Vec<JsAccountInfoExtended>,
426
+ }
427
+
428
+ impl JsGetAccounts {
429
+ pub fn new(next_offset: Option<u64>, accounts: Vec<AccountInfoExtended>) -> Self {
430
+ let next_offset = match next_offset {
431
+ Some(next_offset) => Some(next_offset.into()),
432
+ None => None,
433
+ };
434
+
435
+ let mut mapped = Vec::with_capacity(accounts.len());
436
+ for account in accounts {
437
+ mapped.push(JsAccountInfoExtended::new(account));
438
+ }
439
+
440
+ JsGetAccounts {
441
+ next_offset,
442
+ accounts: mapped,
443
+ }
444
+ }
445
+ }
446
+
447
+ #[napi(object)]
448
+ pub struct JsGetLegacyColdWallets {
449
+ pub next_offset: Option<BigInt>,
450
+ pub wallets: Vec<JsLegacyColdWallet>,
451
+ }
452
+
453
+ impl JsGetLegacyColdWallets {
454
+ pub fn new(next_offset: Option<u64>, wallets: Vec<LegacyColdWallet>) -> Self {
455
+ let next_offset = match next_offset {
456
+ Some(next_offset) => Some(next_offset.into()),
457
+ None => None,
458
+ };
459
+
460
+ let mut mapped = Vec::with_capacity(wallets.len());
461
+ for wallet in wallets {
462
+ mapped.push(JsLegacyColdWallet::new(wallet));
463
+ }
464
+
465
+ JsGetLegacyColdWallets {
466
+ next_offset,
467
+ wallets: mapped,
468
+ }
469
+ }
470
+ }
471
+
472
+ #[napi(object)]
473
+ pub struct JsGetReceipts {
474
+ pub next_offset: Option<BigInt>,
475
+ pub receipts: Vec<JsTransactionReceipt>,
476
+ }
477
+
478
+ impl JsGetReceipts {
479
+ pub fn new(
480
+ next_offset: Option<u64>,
481
+ receipts_by_block_number: Vec<(u64, Vec<(B256, TxReceipt)>)>,
482
+ ) -> anyhow::Result<Self> {
483
+ let next_offset = match next_offset {
484
+ Some(next_offset) => Some(next_offset.into()),
485
+ None => None,
486
+ };
487
+
488
+ let mut mapped = vec![];
489
+ for (block_number, tx_receipts) in receipts_by_block_number {
490
+ for (hash, tx_receipt) in tx_receipts {
491
+ let mut receipt = JsTransactionReceipt::new(tx_receipt);
492
+
493
+ receipt.block_number = Some(block_number.into());
494
+ receipt.tx_hash = Some(format!("{:x}", hash));
495
+
496
+ mapped.push(receipt);
497
+ }
498
+ }
499
+
500
+ Ok(JsGetReceipts {
501
+ next_offset,
502
+ receipts: mapped,
503
+ })
504
+ }
505
+ }
506
+
507
+ #[napi(object)]
508
+ pub struct JsGetReceipt {
509
+ pub receipt: Option<JsTransactionReceipt>,
510
+ }
511
+
512
+ impl JsGetReceipt {
513
+ pub fn new(receipt: Option<TxReceipt>, block_number: u64, tx_hash: B256) -> Self {
514
+ let receipt = match receipt {
515
+ Some(receipt) => {
516
+ let mut receipt = JsTransactionReceipt::new(receipt);
517
+ receipt.block_number = Some(block_number.into());
518
+ receipt.tx_hash = Some(tx_hash.to_string());
519
+
520
+ Some(receipt)
521
+ }
522
+ None => None,
523
+ };
524
+
525
+ JsGetReceipt { receipt }
526
+ }
527
+ }
528
+
529
+ #[napi(object)]
530
+ pub struct JsGetState {
531
+ pub block_number: BigInt,
532
+ pub total_round: BigInt,
533
+ }
534
+
535
+ impl JsGetState {
536
+ pub fn new(state: (u64, u64)) -> Self {
537
+ JsGetState {
538
+ block_number: state.0.into(),
539
+ total_round: state.1.into(),
540
+ }
541
+ }
542
+ }
@@ -0,0 +1,71 @@
1
+ use anyhow;
2
+ use mainsail_evm_core::{db::BlsSig, legacy::LegacyAddress};
3
+ use napi::bindgen_prelude::{BigInt, Buffer};
4
+ use revm::primitives::{Address, B256, Bytes, U256, hex};
5
+ use std::str::FromStr;
6
+
7
+ pub(crate) fn create_address_from_string(str: &str) -> anyhow::Result<Address> {
8
+ Ok(Address::from_str(str)?)
9
+ }
10
+
11
+ pub(crate) fn create_legacy_address_from_string(str: &str) -> anyhow::Result<LegacyAddress> {
12
+ LegacyAddress::try_from(str).map_err(|err| anyhow::anyhow!("legacy address parse: {:?}", err))
13
+ }
14
+
15
+ pub(crate) fn convert_js_buffer_to_bytes(buffer: Buffer) -> Bytes {
16
+ Bytes::from_iter(buffer.as_ref())
17
+ }
18
+
19
+ pub(crate) fn convert_string_to_b256(str: String) -> anyhow::Result<B256> {
20
+ Ok(B256::try_from(
21
+ &Bytes::from_str(str.as_str())?.as_ref()[..],
22
+ )?)
23
+ }
24
+
25
+ pub(crate) fn convert_string_to_bls_sig(str: String) -> anyhow::Result<BlsSig> {
26
+ Ok(BlsSig::try_from(
27
+ &Bytes::from_str(str.as_str())?.as_ref()[..],
28
+ )?)
29
+ }
30
+
31
+ pub(crate) fn convert_hex_to_u256(str: &str) -> U256 {
32
+ U256::from_le_slice(&hex::decode(&str).expect("valid hex")[..])
33
+ }
34
+
35
+ pub(crate) fn convert_u256_to_hex(value: U256) -> String {
36
+ hex::encode(value.to_le_bytes_vec())
37
+ }
38
+
39
+ pub(crate) fn convert_bigint_to_u256(bigint: BigInt) -> anyhow::Result<U256> {
40
+ let bytes: Vec<u8> = bigint
41
+ .words
42
+ .iter()
43
+ .flat_map(|word| word.to_le_bytes())
44
+ .collect();
45
+
46
+ U256::try_from_le_slice(&bytes[..]).ok_or_else(|| anyhow::anyhow!("invalid bigint"))
47
+ }
48
+
49
+ pub(crate) fn convert_bytes_to_js_buffer(bytes: Bytes) -> Buffer {
50
+ Into::<Vec<u8>>::into(bytes).into()
51
+ }
52
+
53
+ pub(crate) fn convert_u256_to_bigint(value: U256) -> BigInt {
54
+ let slice = value.as_le_slice();
55
+
56
+ const WORD_SIZE: usize = 8;
57
+ assert!(slice.len() % WORD_SIZE == 0);
58
+
59
+ // https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words
60
+ let mut words: Vec<u64> = Vec::with_capacity(slice.len() / WORD_SIZE);
61
+ for chunk in slice.chunks_exact(WORD_SIZE) {
62
+ let mut bytes = [0; 8];
63
+ bytes.copy_from_slice(chunk);
64
+ words.push(u64::from_le_bytes(bytes));
65
+ }
66
+
67
+ BigInt {
68
+ words,
69
+ sign_bit: false,
70
+ }
71
+ }