@@ -24,6 +24,7 @@ interface DebugLayoutProps {
2424 callTree ?: any
2525 debugWithGeneratedSources ?: boolean
2626 onDebugWithGeneratedSourcesChange ?: ( checked : boolean ) => void
27+ registerEvent ?: any
2728}
2829
2930export const DebugLayout = ( {
@@ -45,9 +46,10 @@ export const DebugLayout = ({
4546 stepManager,
4647 callTree,
4748 debugWithGeneratedSources,
48- onDebugWithGeneratedSourcesChange
49+ onDebugWithGeneratedSourcesChange,
50+ registerEvent
4951} : DebugLayoutProps ) => {
50- const [ activeObjectTab , setActiveObjectTab ] = useState < 'json ' | 'raw ' > ( 'json ' )
52+ const [ activeObjectTab , setActiveObjectTab ] = useState < 'stateLocals ' | 'stackMemory ' > ( 'stateLocals ' )
5153 const [ copyTooltips , setCopyTooltips ] = useState < { [ key : string ] : string } > ( {
5254 from : 'Copy address' ,
5355 to : 'Copy address'
@@ -60,6 +62,10 @@ export const DebugLayout = ({
6062 callTrace : true ,
6163 parametersReturnValues : true
6264 } )
65+ const [ stackData , setStackData ] = useState < any > ( null )
66+ const [ memoryData , setMemoryData ] = useState < any > ( null )
67+ const [ callStackData , setCallStackData ] = useState < any > ( null )
68+ const [ opcodeData , setOpcodeData ] = useState < any > ( null )
6369
6470 // Auto-expand sender node when nestedScopes are loaded
6571 React . useEffect ( ( ) => {
@@ -68,6 +74,27 @@ export const DebugLayout = ({
6874 }
6975 } , [ nestedScopes ] )
7076
77+ // Register event listeners for stack, memory, call stack, and opcodes
78+ React . useEffect ( ( ) => {
79+ if ( registerEvent ) {
80+ registerEvent ( 'traceManagerStackUpdate' , ( stack : any ) => {
81+ setStackData ( stack )
82+ } )
83+
84+ registerEvent ( 'traceManagerMemoryUpdate' , ( memory : any ) => {
85+ setMemoryData ( memory )
86+ } )
87+
88+ registerEvent ( 'traceManagerCallStackUpdate' , ( callStack : any ) => {
89+ setCallStackData ( callStack )
90+ } )
91+
92+ registerEvent ( 'codeManagerChanged' , ( code : any ) => {
93+ setOpcodeData ( code )
94+ } )
95+ }
96+ } , [ registerEvent ] )
97+
7198 const toggleSection = ( section : 'transactionDetails' | 'callTrace' | 'parametersReturnValues' ) => {
7299 setExpandedSections ( prev => ( {
73100 ...prev ,
@@ -748,58 +775,49 @@ export const DebugLayout = ({
748775 }
749776
750777 const renderObjectContent = ( ) => {
751- const tx = currentTransaction
752-
753- // Get input data (can be either 'data' or 'input' property)
754- const inputData = tx ?. data || tx ?. input
778+ if ( activeObjectTab === 'stateLocals' ) {
779+ // State & Locals tab - show parameters, locals, state
780+ const tx = currentTransaction
781+ const inputData = tx ?. data || tx ?. input
782+
783+ // Extract and decode parameters
784+ let parameters : any = 'N/A'
785+
786+ // First, try to get decoded parameters from solidityLocals
787+ if ( solidityLocals && typeof solidityLocals === 'object' ) {
788+ const decodedParams : any = { }
789+ let hasParams = false
790+
791+ // Iterate through locals to find parameters
792+ for ( const [ key , value ] of Object . entries ( solidityLocals ) ) {
793+ if ( key !== 'length' && key !== 'decode' ) {
794+ decodedParams [ key ] = value
795+ hasParams = true
796+ }
797+ }
755798
756- // Extract and decode parameters
757- let parameters : any = 'N/A'
758-
759- // First, try to get decoded parameters from solidityLocals
760- if ( solidityLocals && typeof solidityLocals === 'object' ) {
761- const decodedParams : any = { }
762- let hasParams = false
763-
764- // Iterate through locals to find parameters
765- for ( const [ key , value ] of Object . entries ( solidityLocals ) ) {
766- // Check if this is a parameter (either by checking a flag or by convention)
767- // Parameters are typically stored as local variables
768- if ( key !== 'length' && key !== 'decode' ) {
769- decodedParams [ key ] = value
770- hasParams = true
799+ if ( hasParams ) {
800+ parameters = decodedParams
771801 }
772802 }
773803
774- if ( hasParams ) {
775- parameters = decodedParams
804+ // Fallback to raw hex if no decoded params available
805+ if ( parameters === 'N/A' && tx && inputData ) {
806+ if ( inputData === '0x' || inputData === '' ) {
807+ parameters = ! tx . to ? 'Contract Bytecode' : 'None (ETH Transfer)'
808+ } else if ( inputData . length > 10 ) {
809+ parameters = '0x' + inputData . substring ( 10 )
810+ } else {
811+ parameters = inputData
812+ }
776813 }
777- }
778814
779- // Fallback to raw hex if no decoded params available
780- if ( parameters === 'N/A' && tx && inputData ) {
781- if ( inputData === '0x' || inputData === '' ) {
782- parameters = ! tx . to ? 'Contract Bytecode' : 'None (ETH Transfer)'
783- } else if ( inputData . length > 10 ) {
784- // Strip the function selector (first 10 chars including '0x')
785- parameters = '0x' + inputData . substring ( 10 )
786- } else {
787- parameters = inputData
815+ const objectData : any = {
816+ parameters : parameters ,
817+ locals : solidityLocals || 'No local variables at current step' ,
818+ state : solidityState || 'No state variables at current step'
788819 }
789- }
790-
791- // Debug logging
792- console . log ( '[DebugLayout] solidityLocals:' , solidityLocals )
793- console . log ( '[DebugLayout] solidityState:' , solidityState )
794-
795- // Build objectData
796- const objectData : any = {
797- parameters : parameters ,
798- locals : solidityLocals || 'No local variables at current step' ,
799- state : solidityState || 'No state variables at current step'
800- }
801820
802- if ( activeObjectTab === 'json' ) {
803821 return (
804822 < div className = "debug-object-content json-renderer" >
805823 < div className = "json-line" >
@@ -827,10 +845,39 @@ export const DebugLayout = ({
827845 </ div >
828846 )
829847 } else {
848+ // Stack & Memory tab - show opcode, call stack, memory
849+ const stackMemoryData : any = {
850+ opcode : opcodeData || 'No opcode data at current step' ,
851+ callStack : callStackData || 'No call stack at current step' ,
852+ memory : memoryData || 'No memory data at current step' ,
853+ stack : stackData || 'No stack data at current step'
854+ }
855+
830856 return (
831- < pre className = "debug-object-content" >
832- { JSON . stringify ( objectData ) }
833- </ pre >
857+ < div className = "debug-object-content json-renderer" >
858+ < div className = "json-line" >
859+ < span className = "json-bracket" > { '{' } </ span >
860+ </ div >
861+ { Object . keys ( stackMemoryData ) . map ( ( key ) => {
862+ const value = stackMemoryData [ key ]
863+ const path = `root.${ key } `
864+ if ( isObject ( value ) ) {
865+ return renderJsonValue ( value , key , path , 1 )
866+ }
867+ return (
868+ < div key = { path } className = "json-line" style = { { marginLeft : '12px' } } >
869+ < span className = "json-expand-icon-placeholder" > </ span >
870+ < span className = "json-key" > "{ key } "</ span >
871+ < span className = "json-separator" > : </ span >
872+ < span className = "json-value" > { JSON . stringify ( value ) } </ span >
873+ { key !== Object . keys ( stackMemoryData ) [ Object . keys ( stackMemoryData ) . length - 1 ] && < span className = "json-comma" > ,</ span > }
874+ </ div >
875+ )
876+ } ) }
877+ < div className = "json-line" >
878+ < span className = "json-bracket" > { '}' } </ span >
879+ </ div >
880+ </ div >
834881 )
835882 }
836883 }
@@ -908,33 +955,28 @@ export const DebugLayout = ({
908955 ) }
909956 </ div >
910957
911- { /* Section 4: Parameters & Return Values */ }
958+ { /* Section 4: State & Locals / Stack & Memory */ }
912959 < div className = "debug-section debug-section-object" style = { ! expandedSections . parametersReturnValues ? { minHeight : 'auto' } : { } } >
913960 < div
914961 className = "debug-section-header"
915962 onClick = { ( ) => toggleSection ( 'parametersReturnValues' ) }
916963 style = { { cursor : 'pointer' } }
917964 >
918- < h6 className = "debug-section-title" >
919- < FormattedMessage id = "debugger.parametersAndReturnValues" defaultMessage = "Parameters & Return Values" />
920- </ h6 >
921- < div style = { { display : 'flex' , alignItems : 'center' , gap : '0.5rem' } } >
922- < i className = { `fas ${ expandedSections . parametersReturnValues ? 'fa-chevron-down' : 'fa-chevron-right' } ` } style = { { fontSize : '0.75rem' , color : 'var(--bs-body-color)' } } > </ i >
923- < div className = "debug-tabs" onClick = { ( e ) => e . stopPropagation ( ) } >
924- < button
925- className = { `debug-tab ${ activeObjectTab === 'json' ? 'active' : '' } ` }
926- onClick = { ( ) => setActiveObjectTab ( 'json' ) }
927- >
928- < FormattedMessage id = "debugger.json" defaultMessage = "JSON" />
929- </ button >
930- < button
931- className = { `debug-tab ${ activeObjectTab === 'raw' ? 'active' : '' } ` }
932- onClick = { ( ) => setActiveObjectTab ( 'raw' ) }
933- >
934- < FormattedMessage id = "debugger.raw" defaultMessage = "Raw" />
935- </ button >
936- </ div >
965+ < div className = "debug-tabs" onClick = { ( e ) => e . stopPropagation ( ) } style = { { paddingLeft : '1rem' } } >
966+ < button
967+ className = { `debug-tab ${ activeObjectTab === 'stateLocals' ? 'active' : '' } ` }
968+ onClick = { ( ) => setActiveObjectTab ( 'stateLocals' ) }
969+ >
970+ < FormattedMessage id = "debugger.stateLocals" defaultMessage = "State & Locals" />
971+ </ button >
972+ < button
973+ className = { `debug-tab ${ activeObjectTab === 'stackMemory' ? 'active' : '' } ` }
974+ onClick = { ( ) => setActiveObjectTab ( 'stackMemory' ) }
975+ >
976+ < FormattedMessage id = "debugger.stackMemory" defaultMessage = "Stack & Memory" />
977+ </ button >
937978 </ div >
979+ < i className = { `fas ${ expandedSections . parametersReturnValues ? 'fa-chevron-down' : 'fa-chevron-right' } ` } style = { { fontSize : '0.75rem' , marginRight : '1rem' , color : 'var(--bs-body-color)' } } > </ i >
938980 </ div >
939981 { expandedSections . parametersReturnValues && (
940982 < div className = "debug-section-content debug-section-scrollable" >
0 commit comments