66 ByteArray ,
77 CairoEnum ,
88 ParsedStruct ,
9+ StructAbi ,
910 Tupled ,
1011} from '../../types' ;
1112import { CairoUint256 } from '../cairoDataTypes/uint256' ;
@@ -24,6 +25,7 @@ import {
2425} from './cairo' ;
2526import {
2627 CairoCustomEnum ,
28+ CairoEnumRaw ,
2729 CairoOption ,
2830 CairoOptionVariant ,
2931 CairoResult ,
@@ -32,6 +34,7 @@ import {
3234import extractTupleMemberTypes from './tuple' ;
3335
3436import { decodeShortString } from '../shortString' ;
37+ import { byteArray } from '.' ;
3538
3639/**
3740 * Parse base types
@@ -76,3 +79,138 @@ function decodeBaseType(type: string, calldata: string | string[]): BigNumberish
7679 return BigInt ( calldata ) ;
7780 }
7881}
82+
83+ /**
84+ * Decode a tuple from calldata.
85+ * @param calldata The calldata array.
86+ * @param typeStr The type string representing the tuple structure.
87+ * @param structs The ABI structs.
88+ * @param enums The ABI enums.
89+ * @returns An array of decoded tuple elements.
90+ */
91+ function decodeTuple ( calldata : string [ ] , typeStr : string , structs : AbiStructs , enums : AbiEnums ) {
92+ // Parse typeStr to understand the tuple structure, e.g., "('felt', 'struct', 'enum')"
93+ const types : string [ ] = extractTupleMemberTypes ( typeStr ) . map ( ( type : string | object ) => String ( type ) ) ;
94+
95+ // Assuming we now have an array of types, ['felt', 'YourStructName', 'YourEnumName'], etc.
96+ const decodedElements = [ ] ;
97+ let calldataIndex = 0 ;
98+
99+ for ( const type of types ) {
100+ switch ( true ) {
101+ case isTypeStruct ( type , structs ) :
102+ let structRes = decodeStruct ( calldata . slice ( calldataIndex , calldataIndex + structs [ type ] . size ) , type , structs , enums ) ;
103+ decodedElements . push ( structRes ) ;
104+ calldataIndex += structs [ type ] . size ; // Assuming size is defined for structs.
105+ break ;
106+ case isTypeEnum ( type , enums ) :
107+ // Determine the expected calldata consumption for the current enum.
108+ const expectedCalldataLength = getExpectedCalldataLengthForEnum ( calldata [ calldataIndex ] , type , enums ) ;
109+ const enumSlice = calldata . slice ( calldataIndex , calldataIndex + expectedCalldataLength ) ;
110+ const enumRes = decodeEnum ( enumSlice , type , enums ) ;
111+ decodedElements . push ( enumRes ) ;
112+ calldataIndex += expectedCalldataLength ; // Move past the consumed calldata.
113+ break ;
114+ case isTypeArray ( type ) :
115+ const arrayType = getArrayType ( type ) ;
116+ const arrayRes = decodeCalldataValue ( [ calldata [ calldataIndex ] ] , arrayType , structs , enums ) ;
117+ decodedElements . push ( arrayRes ) ;
118+ calldataIndex += 1 ;
119+ break ;
120+ default :
121+ const result = decodeBaseType ( type , calldata [ calldataIndex ] ) ;
122+ decodedElements . push ( result ) ;
123+ calldataIndex += 1 ;
124+ }
125+ }
126+
127+ return decodedElements ;
128+ }
129+
130+ function decodeByteArray ( calldata : string [ ] ) : ByteArray {
131+ // Implementation here...
132+ return byteArrayFromString ( calldata . join ( '' ) ) ;
133+ }
134+
135+ function decodeCalldataValue ( calldata : string | string [ ] , type : string , structs : AbiStructs , enums : AbiEnums ) : any {
136+ // Implementation here...
137+ }
138+
139+ function decodeCalldataField ( calldataIterator : Iterator < string > , input : AbiEntry , structs : AbiStructs , enums : AbiEnums ) : any {
140+ // Implementation here...
141+ }
142+
143+ function decodeStruct ( calldataSegment : string [ ] , structName : string , structs : AbiStructs , enums : AbiEnums ) : ParsedStruct {
144+ const structAbi : StructAbi = structs [ structName ] ;
145+ if ( ! structAbi ) {
146+ throw new Error ( `Struct with name ${ structName } not found.` ) ;
147+ }
148+
149+ let index = 0 ;
150+ const result : ParsedStruct = { } ;
151+
152+ for ( const field of structAbi . members ) {
153+ const fieldType = field . type ;
154+ const fieldCalldata = calldataSegment . slice ( index , index + 1 ) ; // This is simplified; complex types might span multiple elements.
155+ result [ field . name ] = decodeCalldataValue ( fieldCalldata [ 0 ] , fieldType , structs , enums ) ;
156+ index ++ ;
157+ }
158+
159+ return result ;
160+ }
161+
162+ function decodeEnum ( calldataValues : string [ ] , enumName : string , enums : AbiEnums ) : CairoEnum {
163+ const enumDefinition = enums [ enumName ] ;
164+ if ( ! enumDefinition ) {
165+ throw new Error ( `Enum with name ${ enumName } not found.` ) ;
166+ }
167+
168+ const variantIndex = parseInt ( calldataValues [ 0 ] , 10 ) ;
169+ if ( variantIndex < 0 || variantIndex >= enumDefinition . variants . length ) {
170+ throw new Error ( `Variant index ${ variantIndex } out of range for enum ${ enumName } .` ) ;
171+ }
172+
173+ const variant = enumDefinition . variants [ variantIndex ] ;
174+
175+ // Determine the enum type and decode accordingly
176+ switch ( enumName ) {
177+ case "CairoOption" :
178+ switch ( variant . name ) {
179+ case "None" :
180+ return new CairoOption ( CairoOptionVariant . None ) ;
181+ default : // "Some"
182+ const someValue = calldataValues [ 1 ] ; // Placeholder for actual decoding logic.
183+ // The decoding of someValue needs to be based on the expected data type.
184+ return new CairoOption ( CairoOptionVariant . Some , someValue ) ; // Assuming someValue decoding logic is implemented elsewhere.
185+ }
186+ case "CairoResult" :
187+ const resultValue = calldataValues [ 1 ] ; // Placeholder for actual decoding logic.
188+
189+ switch ( variant . name ) {
190+ case "Ok" :
191+ return new CairoResult ( CairoResultVariant . Ok , resultValue ) ; // Needs proper decoding based on expected type.
192+ default : // "Err"
193+ return new CairoResult ( CairoResultVariant . Err , resultValue ) ; // Needs proper decoding based on expected type.
194+ }
195+
196+ default : // Handling CairoCustomEnum or simple enum types without associated data.
197+ return new CairoCustomEnum ( { activeVariant : variant . name , variant : variant . name } ) ;
198+ }
199+ }
200+
201+ function getExpectedCalldataLengthForEnum ( variantIndexCalldata : string , enumName : string , enums : AbiEnums ) : number {
202+ const enumDefinition = enums [ enumName ] ;
203+ if ( ! enumDefinition ) throw new Error ( `Enum with name ${ enumName } not found.` ) ;
204+
205+ const variantIndex = parseInt ( variantIndexCalldata , 10 ) ;
206+ const variant = enumDefinition . variants [ variantIndex ] ;
207+
208+ switch ( enumName ) {
209+ case "CairoOption" :
210+ return variant . name === "None" ? 1 : 2 ; // "None" requires only the index, "Some" requires additional data.
211+ case "CairoResult" :
212+ return 2 ; // Both "Ok" and "Err" require additional data.
213+ default :
214+ return 1 ; // Assuming other enums don't have associated data by default.
215+ }
216+ }
0 commit comments