@@ -67,28 +67,43 @@ func (arguments Arguments) LengthNonIndexed() int {
67
67
return out
68
68
}
69
69
70
+ // NonIndexed returns the arguments with indexed arguments filtered out
71
+ func (arguments Arguments ) NonIndexed () Arguments {
72
+ var ret []Argument
73
+ for _ , arg := range arguments {
74
+ if ! arg .Indexed {
75
+ ret = append (ret , arg )
76
+ }
77
+ }
78
+ return ret
79
+ }
80
+
70
81
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
71
82
func (arguments Arguments ) isTuple () bool {
72
83
return len (arguments ) > 1
73
84
}
74
85
75
86
// Unpack performs the operation hexdata -> Go format
76
87
func (arguments Arguments ) Unpack (v interface {}, data []byte ) error {
77
- if arguments .isTuple () {
78
- return arguments .unpackTuple (v , data )
79
- }
80
- return arguments .unpackAtomic (v , data )
81
- }
82
88
83
- func (arguments Arguments ) unpackTuple (v interface {}, output []byte ) error {
84
89
// make sure the passed value is arguments pointer
85
- valueOf := reflect .ValueOf (v )
86
- if reflect .Ptr != valueOf .Kind () {
90
+ if reflect .Ptr != reflect .ValueOf (v ).Kind () {
87
91
return fmt .Errorf ("abi: Unpack(non-pointer %T)" , v )
88
92
}
93
+ marshalledValues , err := arguments .UnpackValues (data )
94
+ if err != nil {
95
+ return err
96
+ }
97
+ if arguments .isTuple () {
98
+ return arguments .unpackTuple (v , marshalledValues )
99
+ }
100
+ return arguments .unpackAtomic (v , marshalledValues )
101
+ }
102
+
103
+ func (arguments Arguments ) unpackTuple (v interface {}, marshalledValues []interface {}) error {
89
104
90
105
var (
91
- value = valueOf .Elem ()
106
+ value = reflect . ValueOf ( v ) .Elem ()
92
107
typ = value .Type ()
93
108
kind = value .Kind ()
94
109
)
@@ -110,30 +125,9 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
110
125
exists [field ] = true
111
126
}
112
127
}
113
- // `i` counts the nonindexed arguments.
114
- // `j` counts the number of complex types.
115
- // both `i` and `j` are used to to correctly compute `data` offset.
128
+ for i , arg := range arguments .NonIndexed () {
116
129
117
- i , j := - 1 , 0
118
- for _ , arg := range arguments {
119
-
120
- if arg .Indexed {
121
- // can't read, continue
122
- continue
123
- }
124
- i ++
125
- marshalledValue , err := toGoType ((i + j )* 32 , arg .Type , output )
126
- if err != nil {
127
- return err
128
- }
129
-
130
- if arg .Type .T == ArrayTy {
131
- // combined index ('i' + 'j') need to be adjusted only by size of array, thus
132
- // we need to decrement 'j' because 'i' was incremented
133
- j += arg .Type .Size - 1
134
- }
135
-
136
- reflectValue := reflect .ValueOf (marshalledValue )
130
+ reflectValue := reflect .ValueOf (marshalledValues [i ])
137
131
138
132
switch kind {
139
133
case reflect .Struct :
@@ -166,34 +160,72 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error {
166
160
}
167
161
168
162
// unpackAtomic unpacks ( hexdata -> go ) a single value
169
- func (arguments Arguments ) unpackAtomic (v interface {}, output []byte ) error {
170
- // make sure the passed value is arguments pointer
171
- valueOf := reflect .ValueOf (v )
172
- if reflect .Ptr != valueOf .Kind () {
173
- return fmt .Errorf ("abi: Unpack(non-pointer %T)" , v )
174
- }
175
- arg := arguments [0 ]
176
- if arg .Indexed {
177
- return fmt .Errorf ("abi: attempting to unpack indexed variable into element." )
163
+ func (arguments Arguments ) unpackAtomic (v interface {}, marshalledValues []interface {}) error {
164
+ if len (marshalledValues ) != 1 {
165
+ return fmt .Errorf ("abi: wrong length, expected single value, got %d" , len (marshalledValues ))
178
166
}
167
+ elem := reflect .ValueOf (v ).Elem ()
168
+ reflectValue := reflect .ValueOf (marshalledValues [0 ])
169
+ return set (elem , reflectValue , arguments .NonIndexed ()[0 ])
170
+ }
179
171
180
- value := valueOf .Elem ()
172
+ // Computes the full size of an array;
173
+ // i.e. counting nested arrays, which count towards size for unpacking.
174
+ func getArraySize (arr * Type ) int {
175
+ size := arr .Size
176
+ // Arrays can be nested, with each element being the same size
177
+ arr = arr .Elem
178
+ for arr .T == ArrayTy {
179
+ // Keep multiplying by elem.Size while the elem is an array.
180
+ size *= arr .Size
181
+ arr = arr .Elem
182
+ }
183
+ // Now we have the full array size, including its children.
184
+ return size
185
+ }
181
186
182
- marshalledValue , err := toGoType (0 , arg .Type , output )
183
- if err != nil {
184
- return err
187
+ // UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
188
+ // without supplying a struct to unpack into. Instead, this method returns a list containing the
189
+ // values. An atomic argument will be a list with one element.
190
+ func (arguments Arguments ) UnpackValues (data []byte ) ([]interface {}, error ) {
191
+ retval := make ([]interface {}, 0 , arguments .LengthNonIndexed ())
192
+ virtualArgs := 0
193
+ for index , arg := range arguments .NonIndexed () {
194
+ marshalledValue , err := toGoType ((index + virtualArgs )* 32 , arg .Type , data )
195
+ if arg .Type .T == ArrayTy {
196
+ // If we have a static array, like [3]uint256, these are coded as
197
+ // just like uint256,uint256,uint256.
198
+ // This means that we need to add two 'virtual' arguments when
199
+ // we count the index from now on.
200
+ //
201
+ // Array values nested multiple levels deep are also encoded inline:
202
+ // [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
203
+ //
204
+ // Calculate the full array size to get the correct offset for the next argument.
205
+ // Decrement it by 1, as the normal index increment is still applied.
206
+ virtualArgs += getArraySize (& arg .Type ) - 1
207
+ }
208
+ if err != nil {
209
+ return nil , err
210
+ }
211
+ retval = append (retval , marshalledValue )
185
212
}
186
- return set ( value , reflect . ValueOf ( marshalledValue ), arg )
213
+ return retval , nil
187
214
}
188
215
189
- // Unpack performs the operation Go format -> Hexdata
216
+ // PackValues performs the operation Go format -> Hexdata
217
+ // It is the semantic opposite of UnpackValues
218
+ func (arguments Arguments ) PackValues (args []interface {}) ([]byte , error ) {
219
+ return arguments .Pack (args ... )
220
+ }
221
+
222
+ // Pack performs the operation Go format -> Hexdata
190
223
func (arguments Arguments ) Pack (args ... interface {}) ([]byte , error ) {
191
224
// Make sure arguments match up and pack them
192
225
abiArgs := arguments
193
226
if len (args ) != len (abiArgs ) {
194
227
return nil , fmt .Errorf ("argument count mismatch: %d for %d" , len (args ), len (abiArgs ))
195
228
}
196
-
197
229
// variable input is the output appended at the end of packed
198
230
// output. This is used for strings and bytes types input.
199
231
var variableInput []byte
@@ -207,7 +239,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
207
239
inputOffset += 32
208
240
}
209
241
}
210
-
211
242
var ret []byte
212
243
for i , a := range args {
213
244
input := abiArgs [i ]
@@ -216,7 +247,6 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
216
247
if err != nil {
217
248
return nil , err
218
249
}
219
-
220
250
// check for a slice type (string, bytes, slice)
221
251
if input .Type .requiresLengthPrefix () {
222
252
// calculate the offset
0 commit comments