refactor: move brother_node development artifact to dev/test-nodes subdirectory

Development Artifact Cleanup:
 BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location
- dev/test-nodes/brother_node/: Moved from root directory for better organization
- Contains development configuration, test logs, and test chain data
- No impact on production systems - purely development/testing artifact

 DEVELOPMENT ARTIFACTS IDENTIFIED:
- Chain ID: aitbc-brother-chain (test/development chain)
- Ports: 8010 (P2P) and 8011 (RPC) - different from production
- Environment: .env file with test configuration
- Logs: rpc.log and node.log from development testing session (March 15, 2026)

 ROOT DIRECTORY CLEANUP: Removed development clutter from production directory
- brother_node/ moved to dev/test-nodes/brother_node/
- Root directory now contains only production-ready components
- Development artifacts properly organized in dev/ subdirectory

DIRECTORY STRUCTURE IMPROVEMENT:
📁 dev/test-nodes/: Development and testing node configurations
🏗️ Root Directory: Clean production structure with only essential components
🧪 Development Isolation: Test environments separated from production

BENEFITS:
 Clean Production Directory: No development artifacts in root
 Better Organization: Development nodes grouped in dev/ subdirectory
 Clear Separation: Production vs development environments clearly distinguished
 Maintainability: Easier to identify and manage development components

RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
2026-03-30 17:09:06 +02:00
parent bf730dcb4a
commit 816e258d4c
11734 changed files with 2001707 additions and 0 deletions

61
dev/env/node_modules/@nomicfoundation/edr/src/trace/debug.rs generated vendored Executable file
View File

@@ -0,0 +1,61 @@
//! Port of `hardhat-network/stack-traces/debug.ts` from Hardhat.
use napi::bindgen_prelude::Either25;
use napi_derive::napi;
use super::solidity_stack_trace::{RevertErrorStackTraceEntry, SolidityStackTrace};
use crate::trace::return_data::ReturnData;
#[napi(catch_unwind)]
fn print_stack_trace(trace: SolidityStackTrace) -> napi::Result<()> {
let entry_values = trace
.into_iter()
.map(|entry| match entry {
Either25::A(entry) => serde_json::to_value(entry),
Either25::B(entry) => serde_json::to_value(entry),
Either25::C(entry) => serde_json::to_value(entry),
Either25::D(entry) => serde_json::to_value(entry),
Either25::F(entry) => serde_json::to_value(entry),
Either25::G(entry) => serde_json::to_value(entry),
Either25::H(entry) => serde_json::to_value(entry),
Either25::I(entry) => serde_json::to_value(entry),
Either25::J(entry) => serde_json::to_value(entry),
Either25::K(entry) => serde_json::to_value(entry),
Either25::L(entry) => serde_json::to_value(entry),
Either25::M(entry) => serde_json::to_value(entry),
Either25::N(entry) => serde_json::to_value(entry),
Either25::O(entry) => serde_json::to_value(entry),
Either25::P(entry) => serde_json::to_value(entry),
Either25::Q(entry) => serde_json::to_value(entry),
Either25::R(entry) => serde_json::to_value(entry),
Either25::S(entry) => serde_json::to_value(entry),
Either25::T(entry) => serde_json::to_value(entry),
Either25::U(entry) => serde_json::to_value(entry),
Either25::V(entry) => serde_json::to_value(entry),
Either25::W(entry) => serde_json::to_value(entry),
Either25::X(entry) => serde_json::to_value(entry),
Either25::Y(entry) => serde_json::to_value(entry),
// Decode the error message from the return data
Either25::E(entry @ RevertErrorStackTraceEntry { .. }) => {
use serde::de::Error;
let decoded_error_msg = ReturnData::new(entry.return_data.clone())
.decode_error()
.map_err(|e| {
serde_json::Error::custom(format_args!("Error decoding return data: {e}"))
})?;
let mut value = serde_json::to_value(entry)?;
if let Some(obj) = value.as_object_mut() {
obj.insert("message".to_string(), decoded_error_msg.into());
}
Ok(value)
}
})
.collect::<Result<Vec<_>, _>>()
.map_err(|e| napi::Error::from_reason(format!("Error converting to JSON: {e}")))?;
println!("{}", serde_json::to_string_pretty(&entry_values)?);
Ok(())
}

89
dev/env/node_modules/@nomicfoundation/edr/src/trace/exit.rs generated vendored Executable file
View File

@@ -0,0 +1,89 @@
//! Naive rewrite of `hardhat-network/provider/vm/exit.ts` from Hardhat.
//! Used together with `VmTracer`.
use std::fmt;
use edr_chain_spec::EvmHaltReason;
use napi_derive::napi;
#[napi]
pub struct Exit(pub(crate) ExitCode);
#[napi]
/// Represents the exit code of the EVM.
#[derive(Debug, PartialEq, Eq)]
#[allow(clippy::upper_case_acronyms, non_camel_case_types)] // These are exported and mapped 1:1 to existing JS enum
pub enum ExitCode {
/// Execution was successful.
SUCCESS = 0,
/// Execution was reverted.
REVERT,
/// Execution ran out of gas.
OUT_OF_GAS,
/// Execution encountered an internal error.
INTERNAL_ERROR,
/// Execution encountered an invalid opcode.
INVALID_OPCODE,
/// Execution encountered a stack underflow.
STACK_UNDERFLOW,
/// Create init code size exceeds limit (runtime).
CODESIZE_EXCEEDS_MAXIMUM,
/// Create collision.
CREATE_COLLISION,
/// Unknown halt reason.
UNKNOWN_HALT_REASON,
}
impl fmt::Display for ExitCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExitCode::SUCCESS => write!(f, "Success"),
ExitCode::REVERT => write!(f, "Reverted"),
ExitCode::OUT_OF_GAS => write!(f, "Out of gas"),
ExitCode::INTERNAL_ERROR => write!(f, "Internal error"),
ExitCode::INVALID_OPCODE => write!(f, "Invalid opcode"),
ExitCode::STACK_UNDERFLOW => write!(f, "Stack underflow"),
ExitCode::CODESIZE_EXCEEDS_MAXIMUM => write!(f, "Codesize exceeds maximum"),
ExitCode::CREATE_COLLISION => write!(f, "Create collision"),
ExitCode::UNKNOWN_HALT_REASON => write!(f, "Unknown halt reason"),
}
}
}
#[allow(clippy::fallible_impl_from)] // naively ported for now
impl From<edr_solidity::exit_code::ExitCode<EvmHaltReason>> for ExitCode {
fn from(code: edr_solidity::exit_code::ExitCode<EvmHaltReason>) -> Self {
use edr_solidity::exit_code::ExitCode;
match code {
ExitCode::Success => Self::SUCCESS,
ExitCode::Revert => Self::REVERT,
ExitCode::Halt(EvmHaltReason::OutOfGas(_)) => Self::OUT_OF_GAS,
ExitCode::Halt(EvmHaltReason::OpcodeNotFound | EvmHaltReason::InvalidFEOpcode
// Returned when an opcode is not implemented for the hardfork
| EvmHaltReason::NotActivated) => Self::INVALID_OPCODE,
ExitCode::Halt(EvmHaltReason::StackUnderflow) => Self::STACK_UNDERFLOW,
ExitCode::Halt(EvmHaltReason::CreateContractSizeLimit) => Self::CODESIZE_EXCEEDS_MAXIMUM,
ExitCode::Halt(EvmHaltReason::CreateCollision) => Self::CREATE_COLLISION,
_ => Self::UNKNOWN_HALT_REASON,
}
}
}
#[napi]
impl Exit {
#[napi(catch_unwind, getter)]
pub fn kind(&self) -> ExitCode {
self.0
}
#[napi(catch_unwind)]
pub fn is_error(&self) -> bool {
!matches!(self.0, ExitCode::SUCCESS)
}
#[napi(catch_unwind)]
pub fn get_reason(&self) -> String {
self.0.to_string()
}
}

View File

@@ -0,0 +1,11 @@
use napi_derive::napi;
#[napi(catch_unwind)]
pub fn link_hex_string_bytecode(
code: String,
address: String,
position: u32,
) -> napi::Result<String> {
edr_solidity::library_utils::link_hex_string_bytecode(code, &address, position)
.map_err(|err| napi::Error::from_reason(err.to_string()))
}

59
dev/env/node_modules/@nomicfoundation/edr/src/trace/model.rs generated vendored Executable file
View File

@@ -0,0 +1,59 @@
use std::rc::Rc;
use edr_solidity::build_model::ContractMetadata;
use napi_derive::napi;
use serde::Serialize;
/// Opaque handle to the `Bytecode` struct.
/// Only used on the JS side by the `VmTraceDecoder` class.
// NOTE: Needed, because we store the resolved `Bytecode` in the MessageTrace
// JS plain objects and those need a dedicated (class) type.
#[napi]
pub struct BytecodeWrapper(pub(crate) Rc<ContractMetadata>);
impl BytecodeWrapper {
pub fn new(bytecode: Rc<ContractMetadata>) -> Self {
Self(bytecode)
}
pub fn inner(&self) -> &Rc<ContractMetadata> {
&self.0
}
}
impl std::ops::Deref for BytecodeWrapper {
type Target = ContractMetadata;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, PartialEq, Eq, Serialize)]
#[allow(non_camel_case_types)] // intentionally mimicks the original case in TS
#[allow(clippy::upper_case_acronyms)]
#[napi]
// Mimicks [`edr_solidity::build_model::ContractFunctionType`].
pub enum ContractFunctionType {
CONSTRUCTOR,
FUNCTION,
FALLBACK,
RECEIVE,
GETTER,
MODIFIER,
FREE_FUNCTION,
}
impl From<edr_solidity::build_model::ContractFunctionType> for ContractFunctionType {
fn from(value: edr_solidity::build_model::ContractFunctionType) -> Self {
match value {
edr_solidity::build_model::ContractFunctionType::Constructor => Self::CONSTRUCTOR,
edr_solidity::build_model::ContractFunctionType::Function => Self::FUNCTION,
edr_solidity::build_model::ContractFunctionType::Fallback => Self::FALLBACK,
edr_solidity::build_model::ContractFunctionType::Receive => Self::RECEIVE,
edr_solidity::build_model::ContractFunctionType::Getter => Self::GETTER,
edr_solidity::build_model::ContractFunctionType::Modifier => Self::MODIFIER,
edr_solidity::build_model::ContractFunctionType::FreeFunction => Self::FREE_FUNCTION,
}
}
}

View File

@@ -0,0 +1,96 @@
//! Rewrite of `hardhat-network/provider/return-data.ts` from Hardhat.
use alloy_sol_types::SolError;
use napi::bindgen_prelude::{BigInt, Uint8Array};
use napi_derive::napi;
// Built-in error types
// See <https://docs.soliditylang.org/en/v0.8.26/control-structures.html#error-handling-assert-require-revert-and-exceptions>
alloy_sol_types::sol! {
error Error(string);
error Panic(uint256);
}
#[napi]
pub struct ReturnData {
#[napi(readonly)]
pub value: Uint8Array,
selector: Option<[u8; 4]>,
}
#[napi]
impl ReturnData {
#[napi(catch_unwind, constructor)]
pub fn new(value: Uint8Array) -> Self {
let selector = value
.get(0..4)
.map(|selector| selector.try_into().expect("selector is 4 bytes"));
Self { value, selector }
}
#[napi(catch_unwind)]
pub fn is_empty(&self) -> bool {
self.value.is_empty()
}
pub fn matches_selector(&self, selector: impl AsRef<[u8]>) -> bool {
self.selector
.is_some_and(|value| value == selector.as_ref())
}
#[napi(catch_unwind)]
pub fn is_error_return_data(&self) -> bool {
self.selector == Some(Error::SELECTOR)
}
#[napi(catch_unwind)]
pub fn is_panic_return_data(&self) -> bool {
self.selector == Some(Panic::SELECTOR)
}
#[napi(catch_unwind)]
pub fn decode_error(&self) -> napi::Result<String> {
if self.is_empty() {
return Ok(String::new());
}
if !self.is_error_return_data() {
return Err(napi::Error::new(
napi::Status::InvalidArg,
"VM Exception while processing transaction: Expected return data to be a Error(string)",
));
}
let result = Error::abi_decode(&self.value[..]).map_err(|_err| {
napi::Error::new(
napi::Status::InvalidArg,
"VM Exception while processing transaction: Expected return data to contain a valid string",
)
})?;
Ok(result.0)
}
#[napi(catch_unwind)]
pub fn decode_panic(&self) -> napi::Result<BigInt> {
if !self.is_panic_return_data() {
return Err(napi::Error::new(
napi::Status::InvalidArg,
"VM Exception while processing transaction: Expected return data to be a Panic(uint256)",
));
}
let result = Panic::abi_decode(&self.value[..]).map_err(|_err| {
napi::Error::new(
napi::Status::InvalidArg,
"VM Exception while processing transaction: Expected return data to contain a valid uint256",
)
})?;
Ok(BigInt {
sign_bit: false,
words: result.0.as_limbs().to_vec(),
})
}
}

View File

@@ -0,0 +1,883 @@
//! Naive rewrite of `hardhat-network/stack-traces/solidity-stack-traces.ts`
//! from Hardhat.
use std::convert::Infallible;
use edr_primitives::{hex, U256};
use napi::bindgen_prelude::{BigInt, Either25, FromNapiValue, ToNapiValue, Uint8Array, Undefined};
use napi_derive::napi;
use serde::{Serialize, Serializer};
use super::model::ContractFunctionType;
use crate::{
cast::TryCast, solidity_tests::cheatcode_errors::CheatcodeErrorDetails, trace::u256_to_bigint,
};
#[napi]
#[repr(u8)]
#[allow(non_camel_case_types)] // intentionally mimicks the original case in TS
#[allow(clippy::upper_case_acronyms)]
#[derive(PartialEq, Eq, PartialOrd, Ord, strum::FromRepr, strum::IntoStaticStr, Serialize)]
pub enum StackTraceEntryType {
CALLSTACK_ENTRY = 0,
UNRECOGNIZED_CREATE_CALLSTACK_ENTRY,
UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY,
PRECOMPILE_ERROR,
REVERT_ERROR,
PANIC_ERROR,
CUSTOM_ERROR,
FUNCTION_NOT_PAYABLE_ERROR,
INVALID_PARAMS_ERROR,
FALLBACK_NOT_PAYABLE_ERROR,
FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR,
UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR, /* TODO: Should trying to call a
* private/internal be a special case of
* this? */
MISSING_FALLBACK_OR_RECEIVE_ERROR,
RETURNDATA_SIZE_ERROR,
NONCONTRACT_ACCOUNT_CALLED_ERROR,
CALL_FAILED_ERROR,
DIRECT_LIBRARY_CALL_ERROR,
UNRECOGNIZED_CREATE_ERROR,
UNRECOGNIZED_CONTRACT_ERROR,
OTHER_EXECUTION_ERROR,
// This is a special case to handle a regression introduced in solc 0.6.3
// For more info: https://github.com/ethereum/solidity/issues/9006
UNMAPPED_SOLC_0_6_3_REVERT_ERROR,
CONTRACT_TOO_LARGE_ERROR,
INTERNAL_FUNCTION_CALLSTACK_ENTRY,
CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR,
CHEATCODE_ERROR,
}
#[napi(catch_unwind)]
pub fn stack_trace_entry_type_to_string(val: StackTraceEntryType) -> &'static str {
val.into()
}
#[napi]
pub const FALLBACK_FUNCTION_NAME: &str = "<fallback>";
#[napi]
pub const RECEIVE_FUNCTION_NAME: &str = "<receive>";
#[napi]
pub const CONSTRUCTOR_FUNCTION_NAME: &str = "constructor";
#[napi]
pub const UNRECOGNIZED_FUNCTION_NAME: &str = "<unrecognized-selector>";
#[napi]
pub const UNKNOWN_FUNCTION_NAME: &str = "<unknown>";
#[napi]
pub const PRECOMPILE_FUNCTION_NAME: &str = "<precompile>";
#[napi]
pub const UNRECOGNIZED_CONTRACT_NAME: &str = "<UnrecognizedContract>";
#[napi(object)]
#[derive(Clone, PartialEq, Serialize)]
pub struct SourceReference {
pub source_name: String,
pub source_content: String,
pub contract: Option<String>,
pub function: Option<String>,
pub line: u32,
// [number, number] tuple
pub range: Vec<u32>,
}
impl From<edr_solidity::solidity_stack_trace::SourceReference> for SourceReference {
fn from(value: edr_solidity::solidity_stack_trace::SourceReference) -> Self {
let (range_start, range_end) = value.range;
Self {
source_name: value.source_name,
source_content: value.source_content,
contract: value.contract,
function: value.function,
line: value.line,
range: vec![range_start, range_end],
}
}
}
impl From<edr_solidity::return_data::CheatcodeErrorDetails> for CheatcodeErrorDetails {
fn from(value: edr_solidity::return_data::CheatcodeErrorDetails) -> Self {
Self {
code: value.code.into(),
cheatcode: value.cheatcode,
}
}
}
/// A [`StackTraceEntryType`] constant that is convertible to/from a
/// `napi_value`.
///
/// Since Rust does not allow constants directly as members, we use this wrapper
/// to allow the `StackTraceEntryType` to be used as a member of an interface
/// when defining the N-API bindings.
// NOTE: It's currently not possible to use an enum as const generic parameter,
// so we use the underlying `u8` repr used by the enum.
#[derive(Clone, Copy)]
pub struct StackTraceEntryTypeConst<const ENTRY_TYPE: u8>;
impl<const ENTRY_TYPE: u8> FromNapiValue for StackTraceEntryTypeConst<ENTRY_TYPE> {
unsafe fn from_napi_value(
env: napi::sys::napi_env,
napi_val: napi::sys::napi_value,
) -> napi::Result<Self> {
// SAFETY: The safety concern is propagated in the function signature.
let inner: u8 = unsafe { FromNapiValue::from_napi_value(env, napi_val) }?;
if inner != ENTRY_TYPE {
return Err(napi::Error::new(
napi::Status::InvalidArg,
format!("Expected StackTraceEntryType value: {ENTRY_TYPE}, got: {inner}"),
));
}
Ok(StackTraceEntryTypeConst)
}
}
impl<const ENTRY_TYPE: u8> ToNapiValue for StackTraceEntryTypeConst<ENTRY_TYPE> {
unsafe fn to_napi_value(
env: napi::sys::napi_env,
_val: Self,
) -> napi::Result<napi::sys::napi_value> {
// SAFETY: The safety concern is propagated in the function signature.
unsafe { u8::to_napi_value(env, ENTRY_TYPE) }
}
}
impl<const ENTRY_TYPE: u8> Serialize for StackTraceEntryTypeConst<ENTRY_TYPE> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let inner = StackTraceEntryType::from_repr(ENTRY_TYPE).ok_or_else(|| {
serde::ser::Error::custom(format!("Invalid StackTraceEntryType value: {ENTRY_TYPE}"))
})?;
inner.serialize(serializer)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct CallstackEntryStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CALLSTACK_ENTRY")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CALLSTACK_ENTRY as u8 }>,
pub source_reference: SourceReference,
pub function_type: ContractFunctionType,
}
impl From<CallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: CallstackEntryStackTraceEntry) -> Self {
Either25::A(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnrecognizedCreateCallstackEntryStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNRECOGNIZED_CREATE_CALLSTACK_ENTRY"
)]
pub type_: StackTraceEntryTypeConst<
{ StackTraceEntryType::UNRECOGNIZED_CREATE_CALLSTACK_ENTRY as u8 },
>,
pub source_reference: Option<Undefined>,
}
impl From<UnrecognizedCreateCallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnrecognizedCreateCallstackEntryStackTraceEntry) -> Self {
Either25::B(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnrecognizedContractCallstackEntryStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY"
)]
pub type_: StackTraceEntryTypeConst<
{ StackTraceEntryType::UNRECOGNIZED_CONTRACT_CALLSTACK_ENTRY as u8 },
>,
#[serde(serialize_with = "serialize_uint8array_to_hex")]
pub address: Uint8Array,
pub source_reference: Option<Undefined>,
}
impl From<UnrecognizedContractCallstackEntryStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnrecognizedContractCallstackEntryStackTraceEntry) -> Self {
Either25::C(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct PrecompileErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.PRECOMPILE_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::PRECOMPILE_ERROR as u8 }>,
pub precompile: u32,
pub source_reference: Option<Undefined>,
}
impl From<PrecompileErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: PrecompileErrorStackTraceEntry) -> Self {
Either25::D(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct RevertErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.REVERT_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::REVERT_ERROR as u8 }>,
#[serde(serialize_with = "serialize_uint8array_to_hex")]
pub return_data: Uint8Array,
pub source_reference: SourceReference,
pub is_invalid_opcode_error: bool,
}
impl From<RevertErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: RevertErrorStackTraceEntry) -> Self {
Either25::E(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct PanicErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.PANIC_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::PANIC_ERROR as u8 }>,
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
pub error_code: BigInt,
pub source_reference: Option<SourceReference>,
}
impl From<PanicErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: PanicErrorStackTraceEntry) -> Self {
Either25::F(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct CustomErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CUSTOM_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CUSTOM_ERROR as u8 }>,
// unlike RevertErrorStackTraceEntry, this includes the message already parsed
pub message: String,
pub source_reference: SourceReference,
}
impl From<CustomErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: CustomErrorStackTraceEntry) -> Self {
Either25::G(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct FunctionNotPayableErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.FUNCTION_NOT_PAYABLE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::FUNCTION_NOT_PAYABLE_ERROR as u8 }>,
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
pub value: BigInt,
pub source_reference: SourceReference,
}
impl From<FunctionNotPayableErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: FunctionNotPayableErrorStackTraceEntry) -> Self {
Either25::H(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct InvalidParamsErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.INVALID_PARAMS_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::INVALID_PARAMS_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<InvalidParamsErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: InvalidParamsErrorStackTraceEntry) -> Self {
Either25::I(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct FallbackNotPayableErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.FALLBACK_NOT_PAYABLE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::FALLBACK_NOT_PAYABLE_ERROR as u8 }>,
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
pub value: BigInt,
pub source_reference: SourceReference,
}
impl From<FallbackNotPayableErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: FallbackNotPayableErrorStackTraceEntry) -> Self {
Either25::J(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct FallbackNotPayableAndNoReceiveErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<
{ StackTraceEntryType::FALLBACK_NOT_PAYABLE_AND_NO_RECEIVE_ERROR as u8 },
>,
#[serde(serialize_with = "serialize_evm_value_bigint_using_u256")]
pub value: BigInt,
pub source_reference: SourceReference,
}
impl From<FallbackNotPayableAndNoReceiveErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: FallbackNotPayableAndNoReceiveErrorStackTraceEntry) -> Self {
Either25::K(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR"
)]
pub type_: StackTraceEntryTypeConst<
{ StackTraceEntryType::UNRECOGNIZED_FUNCTION_WITHOUT_FALLBACK_ERROR as u8 },
>,
pub source_reference: SourceReference,
}
impl From<UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry) -> Self {
Either25::L(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct MissingFallbackOrReceiveErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.MISSING_FALLBACK_OR_RECEIVE_ERROR"
)]
pub type_:
StackTraceEntryTypeConst<{ StackTraceEntryType::MISSING_FALLBACK_OR_RECEIVE_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<MissingFallbackOrReceiveErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: MissingFallbackOrReceiveErrorStackTraceEntry) -> Self {
Either25::M(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct ReturndataSizeErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.RETURNDATA_SIZE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::RETURNDATA_SIZE_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<ReturndataSizeErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: ReturndataSizeErrorStackTraceEntry) -> Self {
Either25::N(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct NonContractAccountCalledErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.NONCONTRACT_ACCOUNT_CALLED_ERROR"
)]
pub type_:
StackTraceEntryTypeConst<{ StackTraceEntryType::NONCONTRACT_ACCOUNT_CALLED_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<NonContractAccountCalledErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: NonContractAccountCalledErrorStackTraceEntry) -> Self {
Either25::O(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct CallFailedErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CALL_FAILED_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CALL_FAILED_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<CallFailedErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: CallFailedErrorStackTraceEntry) -> Self {
Either25::P(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct DirectLibraryCallErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.DIRECT_LIBRARY_CALL_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::DIRECT_LIBRARY_CALL_ERROR as u8 }>,
pub source_reference: SourceReference,
}
impl From<DirectLibraryCallErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: DirectLibraryCallErrorStackTraceEntry) -> Self {
Either25::Q(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnrecognizedCreateErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNRECOGNIZED_CREATE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::UNRECOGNIZED_CREATE_ERROR as u8 }>,
#[serde(serialize_with = "serialize_uint8array_to_hex")]
pub return_data: Uint8Array,
pub source_reference: Option<Undefined>,
pub is_invalid_opcode_error: bool,
}
impl From<UnrecognizedCreateErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnrecognizedCreateErrorStackTraceEntry) -> Self {
Either25::R(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnrecognizedContractErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNRECOGNIZED_CONTRACT_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::UNRECOGNIZED_CONTRACT_ERROR as u8 }>,
#[serde(serialize_with = "serialize_uint8array_to_hex")]
pub address: Uint8Array,
#[serde(serialize_with = "serialize_uint8array_to_hex")]
pub return_data: Uint8Array,
pub source_reference: Option<Undefined>,
pub is_invalid_opcode_error: bool,
}
impl From<UnrecognizedContractErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnrecognizedContractErrorStackTraceEntry) -> Self {
Either25::S(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct OtherExecutionErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.OTHER_EXECUTION_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::OTHER_EXECUTION_ERROR as u8 }>,
pub source_reference: Option<SourceReference>,
}
impl From<OtherExecutionErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: OtherExecutionErrorStackTraceEntry) -> Self {
Either25::T(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct UnmappedSolc063RevertErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.UNMAPPED_SOLC_0_6_3_REVERT_ERROR"
)]
pub type_:
StackTraceEntryTypeConst<{ StackTraceEntryType::UNMAPPED_SOLC_0_6_3_REVERT_ERROR as u8 }>,
pub source_reference: Option<SourceReference>,
}
impl From<UnmappedSolc063RevertErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: UnmappedSolc063RevertErrorStackTraceEntry) -> Self {
Either25::U(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct ContractTooLargeErrorStackTraceEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.CONTRACT_TOO_LARGE_ERROR"
)]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CONTRACT_TOO_LARGE_ERROR as u8 }>,
pub source_reference: Option<SourceReference>,
}
impl From<ContractTooLargeErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: ContractTooLargeErrorStackTraceEntry) -> Self {
Either25::V(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct InternalFunctionCallStackEntry {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.INTERNAL_FUNCTION_CALLSTACK_ENTRY"
)]
pub type_:
StackTraceEntryTypeConst<{ StackTraceEntryType::INTERNAL_FUNCTION_CALLSTACK_ENTRY as u8 }>,
pub pc: u32,
pub source_reference: SourceReference,
}
impl From<InternalFunctionCallStackEntry> for SolidityStackTraceEntry {
fn from(val: InternalFunctionCallStackEntry) -> Self {
Either25::W(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct ContractCallRunOutOfGasError {
#[napi(
js_name = "type",
ts_type = "StackTraceEntryType.CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR"
)]
pub type_:
StackTraceEntryTypeConst<{ StackTraceEntryType::CONTRACT_CALL_RUN_OUT_OF_GAS_ERROR as u8 }>,
pub source_reference: Option<SourceReference>,
}
impl From<ContractCallRunOutOfGasError> for SolidityStackTraceEntry {
fn from(val: ContractCallRunOutOfGasError) -> Self {
Either25::X(val)
}
}
#[napi(object)]
#[derive(Clone, Serialize)]
pub struct CheatcodeErrorStackTraceEntry {
#[napi(js_name = "type", ts_type = "StackTraceEntryType.CHEATCODE_ERROR")]
pub type_: StackTraceEntryTypeConst<{ StackTraceEntryType::CHEATCODE_ERROR as u8 }>,
// The parsed cheatcode error message that can be displayed to the user
pub message: String,
pub source_reference: SourceReference,
pub details: Option<CheatcodeErrorDetails>,
}
impl From<CheatcodeErrorStackTraceEntry> for SolidityStackTraceEntry {
fn from(val: CheatcodeErrorStackTraceEntry) -> Self {
Either25::Y(val)
}
}
#[allow(dead_code)]
// NOTE: This ported directly from JS for completeness and is used in the Rust
// side of the bindings. However, napi-rs does not support exporting Rust type
// aliases to the index.d.ts file, and it does not store the type definitions
// when expanding the macros, so to use it we would have to specify this type
// literally (all 26 lines of it) at every #[napi]-exported function, which is
// not ideal.
// Rather, we just bite the bullet for now and use the type alias directly
// (which falls back to `any` as it's not recognized in the context of the
// index.d.ts file) until we finish the porting work.
pub type SolidityStackTraceEntry = Either25<
CallstackEntryStackTraceEntry,
UnrecognizedCreateCallstackEntryStackTraceEntry,
UnrecognizedContractCallstackEntryStackTraceEntry,
PrecompileErrorStackTraceEntry,
RevertErrorStackTraceEntry,
PanicErrorStackTraceEntry,
CustomErrorStackTraceEntry,
FunctionNotPayableErrorStackTraceEntry,
InvalidParamsErrorStackTraceEntry,
FallbackNotPayableErrorStackTraceEntry,
FallbackNotPayableAndNoReceiveErrorStackTraceEntry,
UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry,
MissingFallbackOrReceiveErrorStackTraceEntry,
ReturndataSizeErrorStackTraceEntry,
NonContractAccountCalledErrorStackTraceEntry,
CallFailedErrorStackTraceEntry,
DirectLibraryCallErrorStackTraceEntry,
UnrecognizedCreateErrorStackTraceEntry,
UnrecognizedContractErrorStackTraceEntry,
OtherExecutionErrorStackTraceEntry,
UnmappedSolc063RevertErrorStackTraceEntry,
ContractTooLargeErrorStackTraceEntry,
InternalFunctionCallStackEntry,
ContractCallRunOutOfGasError,
CheatcodeErrorStackTraceEntry,
>;
impl TryCast<SolidityStackTraceEntry> for edr_solidity::solidity_stack_trace::StackTraceEntry {
type Error = Infallible;
fn try_cast(self) -> Result<SolidityStackTraceEntry, Self::Error> {
use edr_solidity::solidity_stack_trace::StackTraceEntry;
let result = match self {
StackTraceEntry::CallstackEntry {
source_reference,
function_type,
} => CallstackEntryStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
function_type: function_type.into(),
}
.into(),
StackTraceEntry::UnrecognizedCreateCallstackEntry => {
UnrecognizedCreateCallstackEntryStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: None,
}
.into()
}
StackTraceEntry::UnrecognizedContractCallstackEntry { address } => {
UnrecognizedContractCallstackEntryStackTraceEntry {
type_: StackTraceEntryTypeConst,
address: Uint8Array::with_data_copied(address),
source_reference: None,
}
.into()
}
StackTraceEntry::PrecompileError { precompile } => PrecompileErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
precompile,
source_reference: None,
}
.into(),
StackTraceEntry::RevertError {
return_data,
source_reference,
is_invalid_opcode_error,
} => RevertErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
return_data: return_data.into(),
source_reference: source_reference.into(),
is_invalid_opcode_error,
}
.into(),
StackTraceEntry::PanicError {
error_code,
source_reference,
} => PanicErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
error_code: u256_to_bigint(&error_code),
source_reference: source_reference.map(std::convert::Into::into),
}
.into(),
StackTraceEntry::CheatCodeError {
message,
source_reference,
details,
} => CheatcodeErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
message,
source_reference: source_reference.into(),
details: details.map(std::convert::Into::into),
}
.into(),
StackTraceEntry::CustomError {
message,
source_reference,
} => CustomErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
message,
source_reference: source_reference.into(),
}
.into(),
StackTraceEntry::FunctionNotPayableError {
value,
source_reference,
} => FunctionNotPayableErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
value: u256_to_bigint(&value),
source_reference: source_reference.into(),
}
.into(),
StackTraceEntry::InvalidParamsError { source_reference } => {
InvalidParamsErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::FallbackNotPayableError {
value,
source_reference,
} => FallbackNotPayableErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
value: u256_to_bigint(&value),
source_reference: source_reference.into(),
}
.into(),
StackTraceEntry::FallbackNotPayableAndNoReceiveError {
value,
source_reference,
} => FallbackNotPayableAndNoReceiveErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
value: u256_to_bigint(&value),
source_reference: source_reference.into(),
}
.into(),
StackTraceEntry::UnrecognizedFunctionWithoutFallbackError { source_reference } => {
UnrecognizedFunctionWithoutFallbackErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::MissingFallbackOrReceiveError { source_reference } => {
MissingFallbackOrReceiveErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::ReturndataSizeError { source_reference } => {
ReturndataSizeErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::NoncontractAccountCalledError { source_reference } => {
NonContractAccountCalledErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::CallFailedError { source_reference } => {
CallFailedErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::DirectLibraryCallError { source_reference } => {
DirectLibraryCallErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.into(),
}
.into()
}
StackTraceEntry::UnrecognizedCreateError {
return_data,
is_invalid_opcode_error,
} => UnrecognizedCreateErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
return_data: return_data.into(),
is_invalid_opcode_error,
source_reference: None,
}
.into(),
StackTraceEntry::UnrecognizedContractError {
address,
return_data,
is_invalid_opcode_error,
} => UnrecognizedContractErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
address: Uint8Array::with_data_copied(address),
return_data: return_data.into(),
is_invalid_opcode_error,
source_reference: None,
}
.into(),
StackTraceEntry::OtherExecutionError { source_reference } => {
OtherExecutionErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.map(std::convert::Into::into),
}
.into()
}
StackTraceEntry::UnmappedSolc0_6_3RevertError { source_reference } => {
UnmappedSolc063RevertErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.map(std::convert::Into::into),
}
.into()
}
StackTraceEntry::ContractTooLargeError { source_reference } => {
ContractTooLargeErrorStackTraceEntry {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.map(std::convert::Into::into),
}
.into()
}
StackTraceEntry::InternalFunctionCallstackEntry {
pc,
source_reference,
} => InternalFunctionCallStackEntry {
type_: StackTraceEntryTypeConst,
pc,
source_reference: source_reference.into(),
}
.into(),
StackTraceEntry::ContractCallRunOutOfGasError { source_reference } => {
ContractCallRunOutOfGasError {
type_: StackTraceEntryTypeConst,
source_reference: source_reference.map(std::convert::Into::into),
}
.into()
}
};
Ok(result)
}
}
#[allow(dead_code)]
// Same as above, but for the `SolidityStackTrace` type.
pub type SolidityStackTrace = Vec<SolidityStackTraceEntry>;
const _: () = {
const fn assert_to_from_napi_value<T: FromNapiValue + ToNapiValue>() {}
assert_to_from_napi_value::<SolidityStackTraceEntry>();
};
/// Serializes a [`BigInt`] that represents an EVM value as a
/// [`edr_primitives::U256`].
fn serialize_evm_value_bigint_using_u256<S>(bigint: &BigInt, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let val = U256::from_limbs_slice(&bigint.words);
val.serialize(s)
}
fn serialize_uint8array_to_hex<S>(uint8array: &Uint8Array, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let hex = hex::encode(uint8array.as_ref());
hex.serialize(s)
}