Skip to content

Commit 736dff6

Browse files
Merge pull request #673 from yaroslavyaroslav/clean-tests-output
Crop all `print` from Tests and Sources.
2 parents 8cffa32 + 1b4ce13 commit 736dff6

28 files changed

+497
-128
lines changed
Lines changed: 394 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,394 @@
1+
//
2+
// Created by Alex Vlasov on 25/10/2018.
3+
// Copyright © 2018 Alex Vlasov. All rights reserved.
4+
//
5+
6+
import Foundation
7+
import BigInt
8+
9+
public extension ABI {
10+
struct Input: Decodable {
11+
public var name: String?
12+
public var type: String
13+
public var indexed: Bool?
14+
public var components: [Input]?
15+
}
16+
17+
struct Output: Decodable {
18+
public var name: String?
19+
public var type: String
20+
public var components: [Output]?
21+
}
22+
23+
struct Record: Decodable {
24+
public var name: String?
25+
public var type: String?
26+
public var payable: Bool?
27+
public var constant: Bool?
28+
public var stateMutability: String?
29+
public var inputs: [ABI.Input]?
30+
public var outputs: [ABI.Output]?
31+
public var anonymous: Bool?
32+
}
33+
34+
enum Element {
35+
public enum ArraySize { // bytes for convenience
36+
case staticSize(UInt64)
37+
case dynamicSize
38+
case notArray
39+
}
40+
41+
case function(Function)
42+
case constructor(Constructor)
43+
case fallback(Fallback)
44+
case event(Event)
45+
case receive(Receive)
46+
case error(EthError)
47+
48+
public enum StateMutability {
49+
case payable
50+
case mutating
51+
case view
52+
case pure
53+
54+
var isConstant: Bool {
55+
switch self {
56+
case .payable:
57+
return false
58+
case .mutating:
59+
return false
60+
default:
61+
return true
62+
}
63+
}
64+
65+
var isPayable: Bool {
66+
switch self {
67+
case .payable:
68+
return true
69+
default:
70+
return false
71+
}
72+
}
73+
}
74+
75+
public struct InOut {
76+
public let name: String
77+
public let type: ParameterType
78+
79+
public init(name: String, type: ParameterType) {
80+
self.name = name
81+
self.type = type
82+
}
83+
}
84+
85+
public struct Function {
86+
public let name: String?
87+
public let inputs: [InOut]
88+
public let outputs: [InOut]
89+
public let stateMutability: StateMutability? = nil
90+
public let constant: Bool
91+
public let payable: Bool
92+
93+
public init(name: String?, inputs: [InOut], outputs: [InOut], constant: Bool, payable: Bool) {
94+
self.name = name
95+
self.inputs = inputs
96+
self.outputs = outputs
97+
self.constant = constant
98+
self.payable = payable
99+
}
100+
}
101+
102+
public struct Constructor {
103+
public let inputs: [InOut]
104+
public let constant: Bool
105+
public let payable: Bool
106+
public init(inputs: [InOut], constant: Bool, payable: Bool) {
107+
self.inputs = inputs
108+
self.constant = constant
109+
self.payable = payable
110+
}
111+
}
112+
113+
public struct Fallback {
114+
public let constant: Bool
115+
public let payable: Bool
116+
117+
public init(constant: Bool, payable: Bool) {
118+
self.constant = constant
119+
self.payable = payable
120+
}
121+
}
122+
123+
public struct Event {
124+
public let name: String
125+
public let inputs: [Input]
126+
public let anonymous: Bool
127+
128+
public init(name: String, inputs: [Input], anonymous: Bool) {
129+
self.name = name
130+
self.inputs = inputs
131+
self.anonymous = anonymous
132+
}
133+
134+
public struct Input {
135+
public let name: String
136+
public let type: ParameterType
137+
public let indexed: Bool
138+
139+
public init(name: String, type: ParameterType, indexed: Bool) {
140+
self.name = name
141+
self.type = type
142+
self.indexed = indexed
143+
}
144+
}
145+
}
146+
public struct Receive {
147+
public let payable: Bool
148+
public let inputs: [InOut]
149+
150+
public init(inputs: [InOut], payable: Bool) {
151+
self.inputs = inputs
152+
self.payable = payable
153+
}
154+
}
155+
/// Custom structured error type available since solidity 0.8.4
156+
public struct EthError {
157+
public let name: String
158+
public let inputs: [Input]
159+
160+
public struct Input {
161+
public let name: String
162+
public let type: ParameterType
163+
164+
public init(name: String, type: ParameterType) {
165+
self.name = name
166+
self.type = type
167+
}
168+
}
169+
}
170+
}
171+
}
172+
173+
// MARK: - Function parameters encoding
174+
175+
extension ABI.Element {
176+
public func encodeParameters(_ parameters: [AnyObject]) -> Data? {
177+
switch self {
178+
case .constructor(let constructor):
179+
return constructor.encodeParameters(parameters)
180+
case .event:
181+
return nil
182+
case .fallback:
183+
return nil
184+
case .function(let function):
185+
return function.encodeParameters(parameters)
186+
case .receive:
187+
return nil
188+
case .error:
189+
return nil
190+
}
191+
}
192+
}
193+
194+
extension ABI.Element.Constructor {
195+
public func encodeParameters(_ parameters: [AnyObject]) -> Data? {
196+
guard parameters.count == inputs.count else { return nil }
197+
return ABIEncoder.encode(types: inputs, values: parameters)
198+
}
199+
}
200+
201+
extension ABI.Element.Function {
202+
203+
/// Encode parameters of a given contract method
204+
/// - Parameter parameters: Parameters to pass to Ethereum contract
205+
/// - Returns: Encoded data
206+
public func encodeParameters(_ parameters: [AnyObject]) -> Data? {
207+
guard parameters.count == inputs.count,
208+
let data = ABIEncoder.encode(types: inputs, values: parameters) else { return nil }
209+
return methodEncoding + data
210+
}
211+
}
212+
213+
// MARK: - Event logs decoding
214+
215+
extension ABI.Element.Event {
216+
public func decodeReturnedLogs(eventLogTopics: [Data], eventLogData: Data) -> [String: Any]? {
217+
guard let eventContent = ABIDecoder.decodeLog(event: self, eventLogTopics: eventLogTopics, eventLogData: eventLogData) else {return nil}
218+
return eventContent
219+
}
220+
}
221+
222+
// MARK: - Function input/output decoding
223+
224+
extension ABI.Element {
225+
public func decodeReturnData(_ data: Data) -> [String: Any]? {
226+
switch self {
227+
case .constructor:
228+
return nil
229+
case .event:
230+
return nil
231+
case .fallback:
232+
return nil
233+
case .function(let function):
234+
return function.decodeReturnData(data)
235+
case .receive:
236+
return nil
237+
case .error:
238+
return nil
239+
}
240+
}
241+
242+
public func decodeInputData(_ data: Data) -> [String: Any]? {
243+
guard data.count == 0 || data.count % 32 == 4 else { return nil }
244+
245+
switch self {
246+
case .constructor(let constructor):
247+
return constructor.decodeInputData(data)
248+
case .event:
249+
return nil
250+
case .fallback:
251+
return nil
252+
case .function(let function):
253+
return function.decodeInputData(data)
254+
case .receive:
255+
return nil
256+
case .error:
257+
return nil
258+
}
259+
}
260+
}
261+
262+
extension ABI.Element.Function {
263+
public func decodeInputData(_ rawData: Data) -> [String: Any]? {
264+
return Core.decodeInputData(rawData, methodEncoding: methodEncoding, inputs: inputs)
265+
}
266+
267+
public func decodeReturnData(_ data: Data) -> [String: Any]? {
268+
// the response size greater than equal 100 bytes, when read function aborted by "require" statement.
269+
// if "require" statement has no message argument, the response is empty (0 byte).
270+
if data.bytes.count >= 100 {
271+
let check00_31 = BigUInt("08C379A000000000000000000000000000000000000000000000000000000000", radix: 16)!
272+
let check32_63 = BigUInt("0000002000000000000000000000000000000000000000000000000000000000", radix: 16)!
273+
274+
// check data[00-31] and data[32-63]
275+
if check00_31 == BigUInt(data[0...31]) && check32_63 == BigUInt(data[32...63]) {
276+
// data.bytes[64-67] contains the length of require message
277+
let len = (Int(data.bytes[64])<<24) | (Int(data.bytes[65])<<16) | (Int(data.bytes[66])<<8) | Int(data.bytes[67])
278+
279+
let message = String(bytes: data.bytes[68..<(68+len)], encoding: .utf8)!
280+
281+
var returnArray = [String: Any]()
282+
283+
// set infomation
284+
returnArray["_abortedByRequire"] = true
285+
returnArray["_errorMessageFromRequire"] = message
286+
287+
// set empty values
288+
for i in 0 ..< outputs.count {
289+
let name = "\(i)"
290+
returnArray[name] = outputs[i].type.emptyValue
291+
if outputs[i].name != "" {
292+
returnArray[outputs[i].name] = outputs[i].type.emptyValue
293+
}
294+
}
295+
296+
return returnArray
297+
}
298+
}
299+
300+
var returnArray = [String: Any]()
301+
302+
// the "require" statement with no message argument will be caught here
303+
if data.count == 0 && outputs.count == 1 {
304+
let name = "0"
305+
let value = outputs[0].type.emptyValue
306+
returnArray[name] = value
307+
if outputs[0].name != "" {
308+
returnArray[outputs[0].name] = value
309+
}
310+
} else {
311+
guard outputs.count * 32 <= data.count else { return nil }
312+
313+
var i = 0
314+
guard let values = ABIDecoder.decode(types: outputs, data: data) else { return nil }
315+
for output in outputs {
316+
let name = "\(i)"
317+
returnArray[name] = values[i]
318+
if output.name != "" {
319+
returnArray[output.name] = values[i]
320+
}
321+
i = i + 1
322+
}
323+
// set a flag to detect the request succeeded
324+
}
325+
326+
if returnArray.isEmpty {
327+
return nil
328+
}
329+
330+
returnArray["_success"] = true
331+
return returnArray
332+
}
333+
}
334+
335+
extension ABI.Element.Constructor {
336+
public func decodeInputData(_ rawData: Data) -> [String: Any]? {
337+
return Core.decodeInputData(rawData, inputs: inputs)
338+
}
339+
}
340+
341+
/// Generic input decoding function.
342+
/// - Parameters:
343+
/// - rawData: data to decode. Must match the followin criteria: `data.count == 0 || data.count % 32 == 4`.
344+
/// - methodEncoding: 4 bytes represeting method signature like `0xFFffFFff`. Can be ommited to avoid checking method encoding.
345+
/// - inputs: expected input types. Order must be the same as in function declaration.
346+
/// - Returns: decoded dictionary of input arguments mapped to their indices and arguments' names if these are not empty.
347+
/// If decoding of at least one argument fails, `rawData` size is invalid or `methodEncoding` doesn't match - `nil` is returned.
348+
private func decodeInputData(_ rawData: Data,
349+
methodEncoding: Data? = nil,
350+
inputs: [ABI.Element.InOut]) -> [String: Any]? {
351+
let data: Data
352+
let sig: Data?
353+
354+
switch rawData.count % 32 {
355+
case 0:
356+
sig = nil
357+
data = Data()
358+
break
359+
case 4:
360+
sig = rawData[0 ..< 4]
361+
data = Data(rawData[4 ..< rawData.count])
362+
default:
363+
return nil
364+
}
365+
366+
if methodEncoding != nil && sig != nil && sig != methodEncoding {
367+
return nil
368+
}
369+
370+
var returnArray = [String: Any]()
371+
372+
if data.count == 0 && inputs.count == 1 {
373+
let name = "0"
374+
let value = inputs[0].type.emptyValue
375+
returnArray[name] = value
376+
if inputs[0].name != "" {
377+
returnArray[inputs[0].name] = value
378+
}
379+
} else {
380+
guard inputs.count * 32 <= data.count else { return nil }
381+
382+
var i = 0
383+
guard let values = ABIDecoder.decode(types: inputs, data: data) else {return nil}
384+
for input in inputs {
385+
let name = "\(i)"
386+
returnArray[name] = values[i]
387+
if input.name != "" {
388+
returnArray[input.name] = values[i]
389+
}
390+
i = i + 1
391+
}
392+
}
393+
return returnArray
394+
}

0 commit comments

Comments
 (0)