@@ -25,14 +25,11 @@ extension Web3 {
25
25
public struct EIP681Parameter {
26
26
public var type : ABI . Element . ParameterType
27
27
public var value : AnyObject
28
- < <<<<<< HEAD
29
- =======
30
28
31
29
public init ( type: ABI . Element . ParameterType , value: AnyObject ) {
32
30
self . type = type
33
31
self . value = value
34
32
}
35
- > >>>>>> c159 f067 ... Make value as any object in eip681 parameters
36
33
}
37
34
public var isPayRequest : Bool
38
35
public var targetAddress : TargetAddress
@@ -108,7 +105,7 @@ extension Web3 {
108
105
if tail == nil {
109
106
return code
110
107
}
111
- guard let components = URLComponents ( string: tail!) else { return code}
108
+ guard let components = URLComponents ( string: tail!. addingPercentEncoding ( withAllowedCharacters : . urlQueryAllowed ) ?? tail! ) else { return code}
112
109
if components. path == " " {
113
110
code. isPayRequest = true
114
111
} else {
@@ -119,72 +116,16 @@ extension Web3 {
119
116
var inputs = [ ABI . Element. InOut] ( )
120
117
for comp in queryItems {
121
118
if let inputType = try ? ABITypeParser . parseTypeString ( comp. name) {
122
- guard let value = comp. value else { continue }
123
- var nativeValue : AnyObject ? = nil
124
- switch inputType {
125
- case . address:
126
- let val = EIP681Code . TargetAddress ( value)
127
- switch val {
128
- case . ethereumAddress( let ethereumAddress) :
129
- nativeValue = ethereumAddress as AnyObject
130
- // default:
131
- // return nil
132
- case . ensAddress( let ens) :
133
- do {
134
- let web = await web3 ( provider: InfuraProvider ( Networks . fromInt ( UInt ( code. chainID ?? 1 ) ) ?? Networks . Mainnet) !)
135
- let ensModel = ENS ( web3: web)
136
- try await ensModel? . setENSResolver ( withDomain: ens)
137
- let address = try await ensModel? . getAddress ( forNode: ens)
138
- nativeValue = address as AnyObject
139
- } catch {
140
- return nil
141
- }
142
- }
143
- case . uint( bits: _) :
144
- if let val = BigUInt ( value, radix: 10 ) {
145
- nativeValue = val as AnyObject
146
- } else if let val = BigUInt ( value. stripHexPrefix ( ) , radix: 16 ) {
147
- nativeValue = val as AnyObject
148
- }
149
- case . int( bits: _) :
150
- if let val = BigInt ( value, radix: 10 ) {
151
- nativeValue = val as AnyObject
152
- } else if let val = BigInt ( value. stripHexPrefix ( ) , radix: 16 ) {
153
- nativeValue = val as AnyObject
154
- }
155
- case . string:
156
- nativeValue = value as AnyObject
157
- case . dynamicBytes:
158
- if let val = Data . fromHex ( value) {
159
- nativeValue = val as AnyObject
160
- } else if let val = value. data ( using: . utf8) {
161
- nativeValue = val as AnyObject
162
- }
163
- case . bytes( length: _) :
164
- if let val = Data . fromHex ( value) {
165
- nativeValue = val as AnyObject
166
- } else if let val = value. data ( using: . utf8) {
167
- nativeValue = val as AnyObject
168
- }
169
- case . bool:
170
- switch value {
171
- case " true " , " True " , " TRUE " , " 1 " :
172
- nativeValue = true as AnyObject
173
- case " false " , " False " , " FALSE " , " 0 " :
174
- nativeValue = false as AnyObject
175
- default :
176
- nativeValue = true as AnyObject
177
- }
178
- default :
179
- continue
180
- }
181
- if nativeValue != nil {
182
- inputs. append ( ABI . Element. InOut ( name: String ( inputNumber) , type: inputType) )
183
- code. parameters. append ( EIP681Code . EIP681Parameter ( type: inputType, value: nativeValue!) )
184
- inputNumber = inputNumber + 1
185
- } else {
186
- return nil
187
- }
119
+ guard let rawValue = comp. value,
120
+ let functionArgument = parseFunctionArgument ( inputType,
121
+ rawValue. trimmingCharacters ( in: . whitespacesAndNewlines) ,
122
+ chainID: code. chainID ?? 0 ,
123
+ inputNumber: inputNumber)
124
+ else { continue }
125
+
126
+ inputs. append ( functionArgument. argType)
127
+ code. parameters. append ( functionArgument. parameter)
128
+ inputNumber = inputNumber + 1
188
129
} else {
189
130
switch comp. name {
190
131
case " value " :
@@ -235,5 +176,196 @@ extension Web3 {
235
176
print ( code)
236
177
return code
237
178
}
179
+
180
+ private static func parseFunctionArgument( _ inputType: ABI . Element . ParameterType ,
181
+ _ rawValue: String ,
182
+ chainID: BigUInt ,
183
+ inputNumber: Int ) -> FunctionArgument ? {
184
+ var parsedValue : AnyObject ? = nil
185
+ switch inputType {
186
+ case . address:
187
+ let val = EIP681Code . TargetAddress ( rawValue)
188
+ switch val {
189
+ case . ethereumAddress( let ethereumAddress) :
190
+ parsedValue = ethereumAddress as AnyObject
191
+ case . ensAddress( let ens) :
192
+ do {
193
+ let web = web3 ( provider: InfuraProvider ( Networks . fromInt ( Int ( chainID) ) ?? Networks . Mainnet) !)
194
+ let ensModel = ENS ( web3: web)
195
+ try ensModel? . setENSResolver ( withDomain: ens)
196
+ let address = try ensModel? . getAddress ( forNode: ens)
197
+ parsedValue = address as AnyObject
198
+ } catch {
199
+ return nil
200
+ }
201
+ }
202
+ case . uint( bits: _) :
203
+ if let val = BigUInt ( rawValue, radix: 10 ) {
204
+ parsedValue = val as AnyObject
205
+ } else if let val = BigUInt ( rawValue. stripHexPrefix ( ) , radix: 16 ) {
206
+ parsedValue = val as AnyObject
207
+ }
208
+ case . int( bits: _) :
209
+ if let val = BigInt ( rawValue, radix: 10 ) {
210
+ parsedValue = val as AnyObject
211
+ } else if let val = BigInt ( rawValue. stripHexPrefix ( ) , radix: 16 ) {
212
+ parsedValue = val as AnyObject
213
+ }
214
+ case . string:
215
+ parsedValue = rawValue as AnyObject
216
+ case . dynamicBytes:
217
+ if let val = Data . fromHex ( rawValue) {
218
+ parsedValue = val as AnyObject
219
+ } else if let val = rawValue. data ( using: . utf8) {
220
+ parsedValue = val as AnyObject
221
+ }
222
+ case . bytes( length: _) :
223
+ if let val = Data . fromHex ( rawValue) {
224
+ parsedValue = val as AnyObject
225
+ } else if let val = rawValue. data ( using: . utf8) {
226
+ parsedValue = val as AnyObject
227
+ }
228
+ case . bool:
229
+ switch rawValue {
230
+ case " true " , " True " , " TRUE " , " 1 " :
231
+ parsedValue = true as AnyObject
232
+ case " false " , " False " , " FALSE " , " 0 " :
233
+ parsedValue = false as AnyObject
234
+ default :
235
+ parsedValue = true as AnyObject
236
+ }
237
+ case let . array( type, length) :
238
+ var rawValues : [ String ] = [ ]
239
+ if case . array = type {
240
+ guard let internalArrays = splitArrayOfArrays ( rawValue) ,
241
+ ( length == 0 || UInt64 ( internalArrays. count) == length) else { return nil }
242
+ rawValues = internalArrays
243
+ } else if case let . tuple( internalTypes) = type {
244
+ // TODO: implement!
245
+ } else if case . string = type {
246
+ guard let strings = splitArrayOfStrings ( rawValue) ,
247
+ ( length == 0 || UInt64 ( strings. count) == length) else { return nil }
248
+ rawValues = strings
249
+ } else {
250
+ let rawValue = String ( rawValue. dropFirst ( ) . dropLast ( ) )
251
+ rawValues = rawValue. split ( separator: " , " ) . map { String ( $0) }
252
+ }
253
+
254
+ parsedValue = rawValues. compactMap {
255
+ parseFunctionArgument ( type,
256
+ String ( $0) ,
257
+ chainID: chainID,
258
+ inputNumber: inputNumber) ?
259
+ . parameter
260
+ . value
261
+ } as AnyObject
262
+
263
+ guard ( parsedValue as? [ AnyObject ] ) ? . count == rawValues. count &&
264
+ ( length == 0 || UInt64 ( rawValues. count) == length) else { return nil }
265
+ case let . tuple( types) :
266
+ // TODO: implement!
267
+ return nil
268
+ default : return nil
269
+ }
270
+
271
+ guard let parsedValue = parsedValue else { return nil }
272
+ return FunctionArgument ( ABI . Element. InOut ( name: String ( inputNumber) , type: inputType) ,
273
+ EIP681Code . EIP681Parameter ( type: inputType, value: parsedValue) )
274
+ }
275
+
276
+ // MARK: - Parsing functions for complex data structures
277
+
278
+ /// Attempts to split given ``rawValue`` into `[String]` where each element of that array
279
+ /// represent a valid, stringified, array in of itself.
280
+ /// With an input like `"[[],[],[]]"` the output is expected to be `["[]","[]","[]"]`.
281
+ /// - Parameter rawValue: supposedly an array of arrays in a form `[[...],[...],...]`
282
+ /// - Returns: separated stringified arrays, or `nil` if separation failed.
283
+ private static func splitArrayOfArrays( _ rawValue: String ) -> [ String ] ? {
284
+ /// Dropping first and last square brackets.
285
+ /// That modifies the upper bound value of the first match of `squareBracketRegex`.
286
+ let rawValue = String ( rawValue. dropFirst ( ) . dropLast ( ) )
287
+
288
+ let squareBracketRegex = try ! NSRegularExpression ( pattern: " ( \\ [*) " )
289
+ let match = squareBracketRegex. firstMatch ( in: rawValue, range: rawValue. fullNSRange)
290
+
291
+ guard let bracketsCount = match? . range. upperBound,
292
+ bracketsCount > 0 else {
293
+ return nil
294
+ }
295
+
296
+ let splitRegex = try ! NSRegularExpression ( pattern: " ( \\ ]){ \( bracketsCount) },( \\ [){ \( bracketsCount) } " )
297
+ var indices : [ Int ] = splitRegex. matches ( in: rawValue, range: rawValue. fullNSRange)
298
+ . map { $0. range. lowerBound + bracketsCount }
299
+ if !indices. isEmpty {
300
+ indices. append ( rawValue. count)
301
+ var prevIndex = 0
302
+ var result = [ String] ( )
303
+ for index in indices {
304
+ result. append ( rawValue [ prevIndex..< index] )
305
+ prevIndex = index + 1
306
+ }
307
+ return result
308
+ }
309
+ return [ rawValue]
310
+ }
311
+
312
+ /// Attempts to split a string that represents an array of strings.
313
+ /// Example:
314
+ ///
315
+ /// // input
316
+ /// "[\"1\",\"abcd,efgh\",\"-=-=-\"]"
317
+ /// // output
318
+ /// ["1","abcd,efgh","-=-=-"]
319
+ ///
320
+ /// // input
321
+ /// "[1,abcd,efgh,-=-=-]"
322
+ /// // output
323
+ /// ["1","abcd","efgh","-=-=-"]
324
+ ///
325
+ /// - Parameter rawValue: stringified array of strings.
326
+ /// - Returns: an array of separated individual elements, or `nil` if separation failed.
327
+ private static func splitArrayOfStrings( _ rawValue: String ) -> [ String ] ? {
328
+ /// Dropping first and last square brackets to exclude them from the first and the last separated element.
329
+ let rawValue = String ( rawValue. dropFirst ( ) . dropLast ( ) )
330
+
331
+ let elementsBoundary = try ! NSRegularExpression ( pattern: " \" , \" " )
332
+ var indices = Array ( elementsBoundary
333
+ . matches ( in: rawValue, range: rawValue. fullNSRange)
334
+ . map { result in
335
+ result. range. lowerBound + 1
336
+ } )
337
+
338
+ if !indices. isEmpty {
339
+ indices. append ( rawValue. count)
340
+ var prevIndex = 0
341
+ var rawValues = [ String] ( )
342
+ for index in indices {
343
+ var argument = rawValue [ prevIndex..< index]
344
+ if let index = argument. firstIndex ( of: " \" " ) ,
345
+ argument. distance ( from: argument. startIndex, to: index) == 0 {
346
+ argument = String ( argument. dropFirst ( ) )
347
+ }
348
+ if let index = argument. lastIndex ( of: " \" " ) ,
349
+ argument. distance ( from: argument. endIndex, to: index) == - 1 {
350
+ argument = String ( argument. dropLast ( ) )
351
+ }
352
+ rawValues. append ( argument)
353
+ prevIndex = index + 1
354
+ }
355
+ return rawValues
356
+ }
357
+ return rawValue. split ( separator: " , " ) . map { String ( $0) }
358
+ }
359
+ }
360
+ }
361
+
362
+ fileprivate class FunctionArgument {
363
+ let argType : ABI . Element . InOut
364
+ let parameter : Web3 . EIP681Code . EIP681Parameter
365
+
366
+ init ( _ argType: ABI . Element . InOut ,
367
+ _ parameter: Web3 . EIP681Code . EIP681Parameter ) {
368
+ self . argType = argType
369
+ self . parameter = parameter
238
370
}
239
371
}
0 commit comments