6
6
ByteArray ,
7
7
CairoEnum ,
8
8
ParsedStruct ,
9
+ StructAbi ,
9
10
Tupled ,
10
11
} from '../../types' ;
11
12
import { CairoUint256 } from '../cairoDataTypes/uint256' ;
@@ -24,6 +25,7 @@ import {
24
25
} from './cairo' ;
25
26
import {
26
27
CairoCustomEnum ,
28
+ CairoEnumRaw ,
27
29
CairoOption ,
28
30
CairoOptionVariant ,
29
31
CairoResult ,
@@ -32,6 +34,7 @@ import {
32
34
import extractTupleMemberTypes from './tuple' ;
33
35
34
36
import { decodeShortString } from '../shortString' ;
37
+ import { byteArray } from '.' ;
35
38
36
39
/**
37
40
* Parse base types
@@ -76,3 +79,138 @@ function decodeBaseType(type: string, calldata: string | string[]): BigNumberish
76
79
return BigInt ( calldata ) ;
77
80
}
78
81
}
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