@nomicfoundation/edr 0.5.2 → 0.6.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/Cargo.toml +7 -0
- package/index.d.ts +277 -1
- package/index.js +23 -1
- package/package.json +44 -35
- package/src/logger.rs +1 -0
- package/src/provider.rs +0 -6
- package/src/trace/compiler.rs +27 -0
- package/src/trace/debug.rs +318 -0
- package/src/trace/error_inferrer.rs +2213 -0
- package/src/trace/exit.rs +86 -0
- package/src/trace/library_utils.rs +6 -0
- package/src/trace/mapped_inlined_internal_functions_heuristics.rs +180 -0
- package/src/trace/message_trace.rs +179 -0
- package/src/trace/model.rs +59 -0
- package/src/trace/return_data.rs +84 -0
- package/src/trace/solidity_stack_trace.rs +694 -0
- package/src/trace/solidity_tracer.rs +315 -0
- package/src/trace/vm_trace_decoder.rs +234 -0
- package/src/trace/vm_tracer.rs +71 -0
- package/src/trace.rs +23 -1
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
//! Naive rewrite of `hardhat-network/stack-traces/solidity-stack-traces.ts`
|
|
2
|
+
//! from Hardhat.
|
|
3
|
+
|
|
4
|
+
use edr_eth::U256;
|
|
5
|
+
use edr_evm::hex;
|
|
6
|
+
use napi::bindgen_prelude::{BigInt, Either24, FromNapiValue, ToNapiValue, Uint8Array, Undefined};
|
|
7
|
+
use napi_derive::napi;
|
|
8
|
+
use serde::{Serialize, Serializer};
|
|
9
|
+
|
|
10
|
+
use super::model::ContractFunctionType;
|
|
11
|
+
|
|
12
|
+
#[napi]
|
|
13
|
+
#[repr(u8)]
|
|
14
|
+
#[allow(non_camel_case_types)] // intentionally mimicks the original case in TS
|
|
15
|
+
#[allow(clippy::upper_case_acronyms)]
|
|
16
|
+
#[derive(PartialEq, Eq, PartialOrd, Ord, strum::FromRepr, strum::IntoStaticStr, Serialize)]
|
|
17
|
+
pub enum StackTraceEntryType {
|
|
18
|
+
CALLSTACK_ENTRY = 0,
|
|
19
|
+
UNRECOGNIZED_CREATE_CALLSTACK_ENTRY,
|
|
20
|
+
UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY,
|
|
21
|
+
PRECOMPILE_ERROR,
|
|
22
|
+
REVERT_ERROR,
|
|
23
|
+
PANIC_ERROR,
|
|
24
|
+
CUSTOM_ERROR,
|
|
25
|
+
FUNCTION_NOT_PAYABLE_ERROR,
|
|
26
|
+
INVALID_PARAMS_ERROR,
|
|
27
|
+
FALLBACK_NOT_PAYABLE_ERROR,
|
|
28
|
+
FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR,
|
|
29
|
+
UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR, /* TODO: Should trying to call a
|
|
30
|
+
* private/internal be a special case of
|
|
31
|
+
* this? */
|
|
32
|
+
MISSING_FALLBACK_OR_RECEIVE_ERROR,
|
|
33
|
+
RETURNDATA_SIZE_ERROR,
|
|
34
|
+
NONCONTRACT_ACCOUNT_CALLED_ERROR,
|
|
35
|
+
CALL_FAILED_ERROR,
|
|
36
|
+
DIRECT_LIBRARY_CALL_ERROR,
|
|
37
|
+
UNRECOGNIZED_CREATE_ERROR,
|
|
38
|
+
UNRECOGNIZED_CONTRACT_ERROR,
|
|
39
|
+
OTHER_EXECUTION_ERROR,
|
|
40
|
+
// This is a special case to handle a regression introduced in solc 0.6.3
|
|
41
|
+
// For more info: https://github.com/ethereum/solidity/issues/9006
|
|
42
|
+
UNMAPPED_SOLC_0_6_3_REVERT_ERROR,
|
|
43
|
+
CONTRACT_TOO_LARGE_ERROR,
|
|
44
|
+
INTERNAL_FUNCTION_CALLSTACK_ENTRY,
|
|
45
|
+
CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[napi]
|
|
49
|
+
pub fn stack_trace_entry_type_to_string(val: StackTraceEntryType) -> &'static str {
|
|
50
|
+
val.into()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#[napi]
|
|
54
|
+
pub const FALLBACK_FUNCTION_NAME: &str = "<fallback>";
|
|
55
|
+
#[napi]
|
|
56
|
+
pub const RECEIVE_FUNCTION_NAME: &str = "<receive>";
|
|
57
|
+
#[napi]
|
|
58
|
+
pub const CONSTRUCTOR_FUNCTION_NAME: &str = "constructor";
|
|
59
|
+
#[napi]
|
|
60
|
+
pub const UNRECOGNIZED_FUNCTION_NAME: &str = "<unrecognized-selector>";
|
|
61
|
+
#[napi]
|
|
62
|
+
pub const UNKNOWN_FUNCTION_NAME: &str = "<unknown>";
|
|
63
|
+
#[napi]
|
|
64
|
+
pub const PRECOMPILE_FUNCTION_NAME: &str = "<precompile>";
|
|
65
|
+
#[napi]
|
|
66
|
+
pub const UNRECOGNIZED_CONTRACT_NAME: &str = "<UnrecognizedContract>";
|
|
67
|
+
|
|
68
|
+
#[napi(object)]
|
|
69
|
+
#[derive(Clone, PartialEq, Serialize)]
|
|
70
|
+
pub struct SourceReference {
|
|
71
|
+
pub source_name: String,
|
|
72
|
+
pub source_content: String,
|
|
73
|
+
pub contract: Option<String>,
|
|
74
|
+
pub function: Option<String>,
|
|
75
|
+
pub line: u32,
|
|
76
|
+
// [number, number] tuple
|
|
77
|
+
pub range: Vec<u32>,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/// A [`StackTraceEntryType`] constant that is convertible to/from a
|
|
81
|
+
/// `napi_value`.
|
|
82
|
+
///
|
|
83
|
+
/// Since Rust does not allow constants directly as members, we use this wrapper
|
|
84
|
+
/// to allow the `StackTraceEntryType` to be used as a member of an interface
|
|
85
|
+
/// when defining the N-API bindings.
|
|
86
|
+
// NOTE: It's currently not possible to use an enum as const generic parameter,
|
|
87
|
+
// so we use the underlying `u8` repr used by the enum.
|
|
88
|
+
#[derive(Clone, Copy)]
|
|
89
|
+
pub struct StackTraceEntryTypeConst<const ENTRY_TYPE: u8>;
|
|
90
|
+
impl<const ENTRY_TYPE: u8> FromNapiValue for StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
91
|
+
unsafe fn from_napi_value(
|
|
92
|
+
env: napi::sys::napi_env,
|
|
93
|
+
napi_val: napi::sys::napi_value,
|
|
94
|
+
) -> napi::Result<Self> {
|
|
95
|
+
let inner: u8 = FromNapiValue::from_napi_value(env, napi_val)?;
|
|
96
|
+
|
|
97
|
+
if inner != ENTRY_TYPE {
|
|
98
|
+
return Err(napi::Error::new(
|
|
99
|
+
napi::Status::InvalidArg,
|
|
100
|
+
format!("Expected StackTraceEntryType value: {ENTRY_TYPE}, got: {inner}"),
|
|
101
|
+
));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
Ok(StackTraceEntryTypeConst)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
impl<const ENTRY_TYPE: u8> ToNapiValue for StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
108
|
+
unsafe fn to_napi_value(
|
|
109
|
+
env: napi::sys::napi_env,
|
|
110
|
+
_val: Self,
|
|
111
|
+
) -> napi::Result<napi::sys::napi_value> {
|
|
112
|
+
u8::to_napi_value(env, ENTRY_TYPE)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
impl<const ENTRY_TYPE: u8> StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
117
|
+
#[allow(clippy::unused_self)] // less verbose than <value as ...>::as_value()
|
|
118
|
+
const fn as_value(&self) -> StackTraceEntryType {
|
|
119
|
+
match StackTraceEntryType::from_repr(ENTRY_TYPE) {
|
|
120
|
+
Some(val) => val,
|
|
121
|
+
None => panic!("Invalid StackTraceEntryType value"),
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
impl<const ENTRY_TYPE: u8> Serialize for StackTraceEntryTypeConst<ENTRY_TYPE> {
|
|
127
|
+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
128
|
+
where
|
|
129
|
+
S: serde::Serializer,
|
|
130
|
+
{
|
|
131
|
+
let inner = StackTraceEntryType::from_repr(ENTRY_TYPE).ok_or_else(|| {
|
|
132
|
+
serde::ser::Error::custom(format!("Invalid StackTraceEntryType value: {ENTRY_TYPE}"))
|
|
133
|
+
})?;
|
|
134
|
+
|
|
135
|
+
inner.serialize(serializer)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
#[napi(object)]
|
|
140
|
+
#[derive(Clone, Serialize)]
|
|
141
|
+
pub struct CallstackEntryStackTraceEntry {
|
|
142
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CALLSTACK_ENTRY")]
|
|
143
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CALLSTACK_ENTRY as u8 }>,
|
|
144
|
+
pub source_reference: SourceReference,
|
|
145
|
+
pub function_type: ContractFunctionType,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
impl From<CallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
|
|
149
|
+
fn from(val: CallstackEntryStackTraceEntry) -> Self {
|
|
150
|
+
Either24::A(val)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[napi(object)]
|
|
155
|
+
#[derive(Clone, Serialize)]
|
|
156
|
+
pub struct UnrecognizedCreateCallstackEntryStackTraceEntry {
|
|
157
|
+
#[napi(
|
|
158
|
+
js_name = "type",
|
|
159
|
+
ts_type = "StackTraceEntryType.UNRECOGNIZED_CREATE_CALLSTACK_ENTRY"
|
|
160
|
+
)]
|
|
161
|
+
pub type_: StackTraceEntryTypeConst<
|
|
162
|
+
{ StackTraceEntryType::UNRECOGNIZED_CREATE_CALLSTACK_ENTRY as u8 },
|
|
163
|
+
>,
|
|
164
|
+
pub source_reference: Option<Undefined>,
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
impl From<UnrecognizedCreateCallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
|
|
168
|
+
fn from(val: UnrecognizedCreateCallstackEntryStackTraceEntry) -> Self {
|
|
169
|
+
Either24::B(val)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[napi(object)]
|
|
174
|
+
#[derive(Clone, Serialize)]
|
|
175
|
+
pub struct UnrecognizedContractCallstackEntryStackTraceEntry {
|
|
176
|
+
#[napi(
|
|
177
|
+
js_name = "type",
|
|
178
|
+
ts_type = "StackTraceEntryType.UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY"
|
|
179
|
+
)]
|
|
180
|
+
pub type_: StackTraceEntryTypeConst<
|
|
181
|
+
{ StackTraceEntryType::UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY as u8 },
|
|
182
|
+
>,
|
|
183
|
+
#[serde(serialize_with = "serialize_uint8array_to_hex")]
|
|
184
|
+
pub address: Uint8Array,
|
|
185
|
+
pub source_reference: Option<Undefined>,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
impl From<UnrecognizedContractCallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
|
|
189
|
+
fn from(val: UnrecognizedContractCallstackEntryStackTraceEntry) -> Self {
|
|
190
|
+
Either24::C(val)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#[napi(object)]
|
|
195
|
+
#[derive(Clone, Serialize)]
|
|
196
|
+
pub struct PrecompileErrorStackTraceEntry {
|
|
197
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.PRECOMPILE_ERROR")]
|
|
198
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::PRECOMPILE_ERROR as u8 }>,
|
|
199
|
+
pub precompile: u32,
|
|
200
|
+
pub source_reference: Option<Undefined>,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
impl From<PrecompileErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
204
|
+
fn from(val: PrecompileErrorStackTraceEntry) -> Self {
|
|
205
|
+
Either24::D(val)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
#[napi(object)]
|
|
210
|
+
#[derive(Clone, Serialize)]
|
|
211
|
+
pub struct RevertErrorStackTraceEntry {
|
|
212
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.REVERT_ERROR")]
|
|
213
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::REVERT_ERROR as u8 }>,
|
|
214
|
+
#[serde(serialize_with = "serialize_uint8array_to_hex")]
|
|
215
|
+
pub return_data: Uint8Array,
|
|
216
|
+
pub source_reference: SourceReference,
|
|
217
|
+
pub is_invalid_opcode_error: bool,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
impl From<RevertErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
221
|
+
fn from(val: RevertErrorStackTraceEntry) -> Self {
|
|
222
|
+
Either24::E(val)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#[napi(object)]
|
|
227
|
+
#[derive(Clone, Serialize)]
|
|
228
|
+
pub struct PanicErrorStackTraceEntry {
|
|
229
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.PANIC_ERROR")]
|
|
230
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::PANIC_ERROR as u8 }>,
|
|
231
|
+
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
|
|
232
|
+
pub error_code: BigInt,
|
|
233
|
+
pub source_reference: Option<SourceReference>,
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
impl From<PanicErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
237
|
+
fn from(val: PanicErrorStackTraceEntry) -> Self {
|
|
238
|
+
Either24::F(val)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#[napi(object)]
|
|
243
|
+
#[derive(Clone, Serialize)]
|
|
244
|
+
pub struct CustomErrorStackTraceEntry {
|
|
245
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CUSTOM_ERROR")]
|
|
246
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CUSTOM_ERROR as u8 }>,
|
|
247
|
+
// unlike RevertErrorStackTraceEntry, this includes the message already parsed
|
|
248
|
+
pub message: String,
|
|
249
|
+
pub source_reference: SourceReference,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
impl From<CustomErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
253
|
+
fn from(val: CustomErrorStackTraceEntry) -> Self {
|
|
254
|
+
Either24::G(val)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#[napi(object)]
|
|
259
|
+
#[derive(Clone, Serialize)]
|
|
260
|
+
pub struct FunctionNotPayableErrorStackTraceEntry {
|
|
261
|
+
#[napi(
|
|
262
|
+
js_name = "type",
|
|
263
|
+
ts_type = "StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR"
|
|
264
|
+
)]
|
|
265
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::FUNCTION_NOT_PAYABLE_ERROR as u8 }>,
|
|
266
|
+
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
|
|
267
|
+
pub value: BigInt,
|
|
268
|
+
pub source_reference: SourceReference,
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
impl From<FunctionNotPayableErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
272
|
+
fn from(val: FunctionNotPayableErrorStackTraceEntry) -> Self {
|
|
273
|
+
Either24::H(val)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#[napi(object)]
|
|
278
|
+
#[derive(Clone, Serialize)]
|
|
279
|
+
pub struct InvalidParamsErrorStackTraceEntry {
|
|
280
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.INVALID_PARAMS_ERROR")]
|
|
281
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::INVALID_PARAMS_ERROR as u8 }>,
|
|
282
|
+
pub source_reference: SourceReference,
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
impl From<InvalidParamsErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
286
|
+
fn from(val: InvalidParamsErrorStackTraceEntry) -> Self {
|
|
287
|
+
Either24::I(val)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
#[napi(object)]
|
|
292
|
+
#[derive(Clone, Serialize)]
|
|
293
|
+
pub struct FallbackNotPayableErrorStackTraceEntry {
|
|
294
|
+
#[napi(
|
|
295
|
+
js_name = "type",
|
|
296
|
+
ts_type = "StackTraceEntryType.FALLBACK_NOT_PAYABLE_ERROR"
|
|
297
|
+
)]
|
|
298
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::FALLBACK_NOT_PAYABLE_ERROR as u8 }>,
|
|
299
|
+
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
|
|
300
|
+
pub value: BigInt,
|
|
301
|
+
pub source_reference: SourceReference,
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
impl From<FallbackNotPayableErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
305
|
+
fn from(val: FallbackNotPayableErrorStackTraceEntry) -> Self {
|
|
306
|
+
Either24::J(val)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#[napi(object)]
|
|
311
|
+
#[derive(Clone, Serialize)]
|
|
312
|
+
pub struct FallbackNotPayableAndNoReceiveErrorStackTraceEntry {
|
|
313
|
+
#[napi(
|
|
314
|
+
js_name = "type",
|
|
315
|
+
ts_type = "StackTraceEntryType.FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR"
|
|
316
|
+
)]
|
|
317
|
+
pub type_: StackTraceEntryTypeConst<
|
|
318
|
+
{ StackTraceEntryType::FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR as u8 },
|
|
319
|
+
>,
|
|
320
|
+
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
|
|
321
|
+
pub value: BigInt,
|
|
322
|
+
pub source_reference: SourceReference,
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
impl From<FallbackNotPayableAndNoReceiveErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
326
|
+
fn from(val: FallbackNotPayableAndNoReceiveErrorStackTraceEntry) -> Self {
|
|
327
|
+
Either24::K(val)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
#[napi(object)]
|
|
332
|
+
#[derive(Clone, Serialize)]
|
|
333
|
+
pub struct UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry {
|
|
334
|
+
#[napi(
|
|
335
|
+
js_name = "type",
|
|
336
|
+
ts_type = "StackTraceEntryType.UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR"
|
|
337
|
+
)]
|
|
338
|
+
pub type_: StackTraceEntryTypeConst<
|
|
339
|
+
{ StackTraceEntryType::UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR as u8 },
|
|
340
|
+
>,
|
|
341
|
+
pub source_reference: SourceReference,
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
impl From<UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
345
|
+
fn from(val: UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry) -> Self {
|
|
346
|
+
Either24::L(val)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
#[napi(object)]
|
|
351
|
+
#[derive(Clone, Serialize)]
|
|
352
|
+
pub struct MissingFallbackOrReceiveErrorStackTraceEntry {
|
|
353
|
+
#[napi(
|
|
354
|
+
js_name = "type",
|
|
355
|
+
ts_type = "StackTraceEntryType.MISSING_FALLBACK_OR_RECEIVE_ERROR"
|
|
356
|
+
)]
|
|
357
|
+
pub type_:
|
|
358
|
+
StackTraceEntryTypeConst<{ StackTraceEntryType::MISSING_FALLBACK_OR_RECEIVE_ERROR as u8 }>,
|
|
359
|
+
pub source_reference: SourceReference,
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
impl From<MissingFallbackOrReceiveErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
363
|
+
fn from(val: MissingFallbackOrReceiveErrorStackTraceEntry) -> Self {
|
|
364
|
+
Either24::M(val)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
#[napi(object)]
|
|
369
|
+
#[derive(Clone, Serialize)]
|
|
370
|
+
pub struct ReturndataSizeErrorStackTraceEntry {
|
|
371
|
+
#[napi(
|
|
372
|
+
js_name = "type",
|
|
373
|
+
ts_type = "StackTraceEntryType.RETURNDATA_SIZE_ERROR"
|
|
374
|
+
)]
|
|
375
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::RETURNDATA_SIZE_ERROR as u8 }>,
|
|
376
|
+
pub source_reference: SourceReference,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
impl From<ReturndataSizeErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
380
|
+
fn from(val: ReturndataSizeErrorStackTraceEntry) -> Self {
|
|
381
|
+
Either24::N(val)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#[napi(object)]
|
|
386
|
+
#[derive(Clone, Serialize)]
|
|
387
|
+
pub struct NonContractAccountCalledErrorStackTraceEntry {
|
|
388
|
+
#[napi(
|
|
389
|
+
js_name = "type",
|
|
390
|
+
ts_type = "StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR"
|
|
391
|
+
)]
|
|
392
|
+
pub type_:
|
|
393
|
+
StackTraceEntryTypeConst<{ StackTraceEntryType::NONCONTRACT_ACCOUNT_CALLED_ERROR as u8 }>,
|
|
394
|
+
pub source_reference: SourceReference,
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
impl From<NonContractAccountCalledErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
398
|
+
fn from(val: NonContractAccountCalledErrorStackTraceEntry) -> Self {
|
|
399
|
+
Either24::O(val)
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
#[napi(object)]
|
|
404
|
+
#[derive(Clone, Serialize)]
|
|
405
|
+
pub struct CallFailedErrorStackTraceEntry {
|
|
406
|
+
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CALL_FAILED_ERROR")]
|
|
407
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CALL_FAILED_ERROR as u8 }>,
|
|
408
|
+
pub source_reference: SourceReference,
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
impl From<CallFailedErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
412
|
+
fn from(val: CallFailedErrorStackTraceEntry) -> Self {
|
|
413
|
+
Either24::P(val)
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
#[napi(object)]
|
|
418
|
+
#[derive(Clone, Serialize)]
|
|
419
|
+
pub struct DirectLibraryCallErrorStackTraceEntry {
|
|
420
|
+
#[napi(
|
|
421
|
+
js_name = "type",
|
|
422
|
+
ts_type = "StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR"
|
|
423
|
+
)]
|
|
424
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::DIRECT_LIBRARY_CALL_ERROR as u8 }>,
|
|
425
|
+
pub source_reference: SourceReference,
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
impl From<DirectLibraryCallErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
429
|
+
fn from(val: DirectLibraryCallErrorStackTraceEntry) -> Self {
|
|
430
|
+
Either24::Q(val)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
#[napi(object)]
|
|
435
|
+
#[derive(Clone, Serialize)]
|
|
436
|
+
pub struct UnrecognizedCreateErrorStackTraceEntry {
|
|
437
|
+
#[napi(
|
|
438
|
+
js_name = "type",
|
|
439
|
+
ts_type = "StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR"
|
|
440
|
+
)]
|
|
441
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::UNRECOGNIZED_CREATE_ERROR as u8 }>,
|
|
442
|
+
#[serde(serialize_with = "serialize_uint8array_to_hex")]
|
|
443
|
+
pub return_data: Uint8Array,
|
|
444
|
+
pub source_reference: Option<Undefined>,
|
|
445
|
+
pub is_invalid_opcode_error: bool,
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
impl From<UnrecognizedCreateErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
449
|
+
fn from(val: UnrecognizedCreateErrorStackTraceEntry) -> Self {
|
|
450
|
+
Either24::R(val)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
#[napi(object)]
|
|
455
|
+
#[derive(Clone, Serialize)]
|
|
456
|
+
pub struct UnrecognizedContractErrorStackTraceEntry {
|
|
457
|
+
#[napi(
|
|
458
|
+
js_name = "type",
|
|
459
|
+
ts_type = "StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR"
|
|
460
|
+
)]
|
|
461
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::UNRECOGNIZED_CONTRACT_ERROR as u8 }>,
|
|
462
|
+
#[serde(serialize_with = "serialize_uint8array_to_hex")]
|
|
463
|
+
pub address: Uint8Array,
|
|
464
|
+
#[serde(serialize_with = "serialize_uint8array_to_hex")]
|
|
465
|
+
pub return_data: Uint8Array,
|
|
466
|
+
pub source_reference: Option<Undefined>,
|
|
467
|
+
pub is_invalid_opcode_error: bool,
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
impl From<UnrecognizedContractErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
471
|
+
fn from(val: UnrecognizedContractErrorStackTraceEntry) -> Self {
|
|
472
|
+
Either24::S(val)
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
#[napi(object)]
|
|
477
|
+
#[derive(Clone, Serialize)]
|
|
478
|
+
pub struct OtherExecutionErrorStackTraceEntry {
|
|
479
|
+
#[napi(
|
|
480
|
+
js_name = "type",
|
|
481
|
+
ts_type = "StackTraceEntryType.OTHER_EXECUTION_ERROR"
|
|
482
|
+
)]
|
|
483
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::OTHER_EXECUTION_ERROR as u8 }>,
|
|
484
|
+
pub source_reference: Option<SourceReference>,
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
impl From<OtherExecutionErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
488
|
+
fn from(val: OtherExecutionErrorStackTraceEntry) -> Self {
|
|
489
|
+
Either24::T(val)
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
#[napi(object)]
|
|
494
|
+
#[derive(Clone, Serialize)]
|
|
495
|
+
pub struct UnmappedSolc063RevertErrorStackTraceEntry {
|
|
496
|
+
#[napi(
|
|
497
|
+
js_name = "type",
|
|
498
|
+
ts_type = "StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR"
|
|
499
|
+
)]
|
|
500
|
+
pub type_:
|
|
501
|
+
StackTraceEntryTypeConst<{ StackTraceEntryType::UNMAPPED_SOLC_0_6_3_REVERT_ERROR as u8 }>,
|
|
502
|
+
pub source_reference: Option<SourceReference>,
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
impl From<UnmappedSolc063RevertErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
506
|
+
fn from(val: UnmappedSolc063RevertErrorStackTraceEntry) -> Self {
|
|
507
|
+
Either24::U(val)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
#[napi(object)]
|
|
512
|
+
#[derive(Clone, Serialize)]
|
|
513
|
+
pub struct ContractTooLargeErrorStackTraceEntry {
|
|
514
|
+
#[napi(
|
|
515
|
+
js_name = "type",
|
|
516
|
+
ts_type = "StackTraceEntryType.CONTRACT_TOO_LARGE_ERROR"
|
|
517
|
+
)]
|
|
518
|
+
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CONTRACT_TOO_LARGE_ERROR as u8 }>,
|
|
519
|
+
pub source_reference: Option<SourceReference>,
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
impl From<ContractTooLargeErrorStackTraceEntry> for SolidityStackTraceEntry {
|
|
523
|
+
fn from(val: ContractTooLargeErrorStackTraceEntry) -> Self {
|
|
524
|
+
Either24::V(val)
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
#[napi(object)]
|
|
529
|
+
#[derive(Clone, Serialize)]
|
|
530
|
+
pub struct InternalFunctionCallStackEntry {
|
|
531
|
+
#[napi(
|
|
532
|
+
js_name = "type",
|
|
533
|
+
ts_type = "StackTraceEntryType.INTERNAL_FUNCTION_CALLSTACK_ENTRY"
|
|
534
|
+
)]
|
|
535
|
+
pub type_:
|
|
536
|
+
StackTraceEntryTypeConst<{ StackTraceEntryType::INTERNAL_FUNCTION_CALLSTACK_ENTRY as u8 }>,
|
|
537
|
+
pub pc: u32,
|
|
538
|
+
pub source_reference: SourceReference,
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
impl From<InternalFunctionCallStackEntry> for SolidityStackTraceEntry {
|
|
542
|
+
fn from(val: InternalFunctionCallStackEntry) -> Self {
|
|
543
|
+
Either24::W(val)
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
#[napi(object)]
|
|
548
|
+
#[derive(Clone, Serialize)]
|
|
549
|
+
pub struct ContractCallRunOutOfGasError {
|
|
550
|
+
#[napi(
|
|
551
|
+
js_name = "type",
|
|
552
|
+
ts_type = "StackTraceEntryType.CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR"
|
|
553
|
+
)]
|
|
554
|
+
pub type_:
|
|
555
|
+
StackTraceEntryTypeConst<{ StackTraceEntryType::CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR as u8 }>,
|
|
556
|
+
pub source_reference: Option<SourceReference>,
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
impl From<ContractCallRunOutOfGasError> for SolidityStackTraceEntry {
|
|
560
|
+
fn from(val: ContractCallRunOutOfGasError) -> Self {
|
|
561
|
+
Either24::X(val)
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
#[allow(dead_code)]
|
|
566
|
+
// NOTE: This ported directly from JS for completeness and is used in the Rust
|
|
567
|
+
// side of the bindings. However, napi-rs does not support exporting Rust type
|
|
568
|
+
// aliases to the index.d.ts file, and it does not store the type definitions
|
|
569
|
+
// when expanding the macros, so to use it we would have to specify this type
|
|
570
|
+
// literally (all 26 lines of it) at every #[napi]-exported function, which is
|
|
571
|
+
// not ideal.
|
|
572
|
+
// Rather, we just bite the bullet for now and use the type alias directly
|
|
573
|
+
// (which falls back to `any` as it's not recognized in the context of the
|
|
574
|
+
// index.d.ts file) until we finish the porting work.
|
|
575
|
+
pub type SolidityStackTraceEntry = Either24<
|
|
576
|
+
CallstackEntryStackTraceEntry,
|
|
577
|
+
UnrecognizedCreateCallstackEntryStackTraceEntry,
|
|
578
|
+
UnrecognizedContractCallstackEntryStackTraceEntry,
|
|
579
|
+
PrecompileErrorStackTraceEntry,
|
|
580
|
+
RevertErrorStackTraceEntry,
|
|
581
|
+
PanicErrorStackTraceEntry,
|
|
582
|
+
CustomErrorStackTraceEntry,
|
|
583
|
+
FunctionNotPayableErrorStackTraceEntry,
|
|
584
|
+
InvalidParamsErrorStackTraceEntry,
|
|
585
|
+
FallbackNotPayableErrorStackTraceEntry,
|
|
586
|
+
FallbackNotPayableAndNoReceiveErrorStackTraceEntry,
|
|
587
|
+
UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry,
|
|
588
|
+
MissingFallbackOrReceiveErrorStackTraceEntry,
|
|
589
|
+
ReturndataSizeErrorStackTraceEntry,
|
|
590
|
+
NonContractAccountCalledErrorStackTraceEntry,
|
|
591
|
+
CallFailedErrorStackTraceEntry,
|
|
592
|
+
DirectLibraryCallErrorStackTraceEntry,
|
|
593
|
+
UnrecognizedCreateErrorStackTraceEntry,
|
|
594
|
+
UnrecognizedContractErrorStackTraceEntry,
|
|
595
|
+
OtherExecutionErrorStackTraceEntry,
|
|
596
|
+
UnmappedSolc063RevertErrorStackTraceEntry,
|
|
597
|
+
ContractTooLargeErrorStackTraceEntry,
|
|
598
|
+
InternalFunctionCallStackEntry,
|
|
599
|
+
ContractCallRunOutOfGasError,
|
|
600
|
+
>;
|
|
601
|
+
|
|
602
|
+
#[allow(dead_code)]
|
|
603
|
+
// Same as above, but for the `SolidityStackTrace` type.
|
|
604
|
+
pub type SolidityStackTrace = Vec<SolidityStackTraceEntry>;
|
|
605
|
+
|
|
606
|
+
pub trait SolidityStackTraceEntryExt {
|
|
607
|
+
fn type_(&self) -> StackTraceEntryType;
|
|
608
|
+
fn source_reference(&self) -> Option<&SourceReference>;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
impl SolidityStackTraceEntryExt for SolidityStackTraceEntry {
|
|
612
|
+
fn type_(&self) -> StackTraceEntryType {
|
|
613
|
+
match self {
|
|
614
|
+
Either24::A(entry) => entry.type_.as_value(),
|
|
615
|
+
Either24::B(entry) => entry.type_.as_value(),
|
|
616
|
+
Either24::C(entry) => entry.type_.as_value(),
|
|
617
|
+
Either24::D(entry) => entry.type_.as_value(),
|
|
618
|
+
Either24::E(entry) => entry.type_.as_value(),
|
|
619
|
+
Either24::F(entry) => entry.type_.as_value(),
|
|
620
|
+
Either24::G(entry) => entry.type_.as_value(),
|
|
621
|
+
Either24::H(entry) => entry.type_.as_value(),
|
|
622
|
+
Either24::I(entry) => entry.type_.as_value(),
|
|
623
|
+
Either24::J(entry) => entry.type_.as_value(),
|
|
624
|
+
Either24::K(entry) => entry.type_.as_value(),
|
|
625
|
+
Either24::L(entry) => entry.type_.as_value(),
|
|
626
|
+
Either24::M(entry) => entry.type_.as_value(),
|
|
627
|
+
Either24::N(entry) => entry.type_.as_value(),
|
|
628
|
+
Either24::O(entry) => entry.type_.as_value(),
|
|
629
|
+
Either24::P(entry) => entry.type_.as_value(),
|
|
630
|
+
Either24::Q(entry) => entry.type_.as_value(),
|
|
631
|
+
Either24::R(entry) => entry.type_.as_value(),
|
|
632
|
+
Either24::S(entry) => entry.type_.as_value(),
|
|
633
|
+
Either24::T(entry) => entry.type_.as_value(),
|
|
634
|
+
Either24::U(entry) => entry.type_.as_value(),
|
|
635
|
+
Either24::V(entry) => entry.type_.as_value(),
|
|
636
|
+
Either24::W(entry) => entry.type_.as_value(),
|
|
637
|
+
Either24::X(entry) => entry.type_.as_value(),
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
#[allow(clippy::unnecessary_lazy_evaluations)] // guards against potential variant reordering
|
|
642
|
+
fn source_reference(&self) -> Option<&SourceReference> {
|
|
643
|
+
match self {
|
|
644
|
+
Either24::A(entry) => Some(&entry.source_reference),
|
|
645
|
+
Either24::B(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
646
|
+
Either24::C(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
647
|
+
Either24::D(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
648
|
+
Either24::E(entry) => Some(&entry.source_reference),
|
|
649
|
+
Either24::F(entry) => entry.source_reference.as_ref(),
|
|
650
|
+
Either24::G(entry) => Some(&entry.source_reference),
|
|
651
|
+
Either24::H(entry) => Some(&entry.source_reference),
|
|
652
|
+
Either24::I(entry) => Some(&entry.source_reference),
|
|
653
|
+
Either24::J(entry) => Some(&entry.source_reference),
|
|
654
|
+
Either24::K(entry) => Some(&entry.source_reference),
|
|
655
|
+
Either24::L(entry) => Some(&entry.source_reference),
|
|
656
|
+
Either24::M(entry) => Some(&entry.source_reference),
|
|
657
|
+
Either24::N(entry) => Some(&entry.source_reference),
|
|
658
|
+
Either24::O(entry) => Some(&entry.source_reference),
|
|
659
|
+
Either24::P(entry) => Some(&entry.source_reference),
|
|
660
|
+
Either24::Q(entry) => Some(&entry.source_reference),
|
|
661
|
+
Either24::R(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
662
|
+
Either24::S(entry) => entry.source_reference.and_then(|_: ()| None),
|
|
663
|
+
Either24::T(entry) => entry.source_reference.as_ref(),
|
|
664
|
+
Either24::U(entry) => entry.source_reference.as_ref(),
|
|
665
|
+
Either24::V(entry) => entry.source_reference.as_ref(),
|
|
666
|
+
Either24::W(entry) => Some(&entry.source_reference),
|
|
667
|
+
Either24::X(entry) => entry.source_reference.as_ref(),
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const _: () = {
|
|
673
|
+
const fn assert_to_from_napi_value<T: FromNapiValue + ToNapiValue>() {}
|
|
674
|
+
assert_to_from_napi_value::<SolidityStackTraceEntry>();
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
/// Serializes a [`BigInt`] that represents an EVM value as a [`edr_eth::U256`].
|
|
678
|
+
fn serialize_evm_value_bigint_using_u256<S>(bigint: &BigInt, s: S) -> Result<S::Ok, S::Error>
|
|
679
|
+
where
|
|
680
|
+
S: Serializer,
|
|
681
|
+
{
|
|
682
|
+
let val = U256::from_limbs_slice(&bigint.words);
|
|
683
|
+
|
|
684
|
+
val.serialize(s)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
fn serialize_uint8array_to_hex<S>(uint8array: &Uint8Array, s: S) -> Result<S::Ok, S::Error>
|
|
688
|
+
where
|
|
689
|
+
S: Serializer,
|
|
690
|
+
{
|
|
691
|
+
let hex = hex::encode(uint8array.as_ref());
|
|
692
|
+
|
|
693
|
+
hex.serialize(s)
|
|
694
|
+
}
|