You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/// Decodes data returned by a function call. Able to decode `revert(message)`, `revert CustomError(...)` and `require(expression, message)` calls.
269
-
/// - Parameter data: bytes returned by a function call.
270
-
/// - Returns: a dictionary containing returned data mappend to indices and names of returned values if these are not `nil`.
268
+
/// Decodes data returned by a function call. Able to decode `revert(string)`, `revert CustomError(...)` and `require(expression, string)` calls.
269
+
/// - Parameters:
270
+
/// - data: bytes returned by a function call;
271
+
/// - errors: optional dictionary of known errors that could be returned by the function you called. Used to decode the error information.
272
+
/// - Returns: a dictionary containing decoded data mappend to indices and names of returned values if these are not `nil`.
273
+
/// If `data` is an error response returns dictionary containing all available information about that specific error. Read more for details.
274
+
///
271
275
/// Return cases:
272
-
/// - when no `outputs` declared: returning `["_success": true]`;
273
-
/// - when `outputs` declared and decoding completed successfully: returning `["_success": true, "0": value_1, "1": value_2, ...]`.
274
-
/// Additionally this dictionary will have mappings to output names if these names are specified in the ABI.
275
-
/// - function call was aborted using `require(some_string_error_message)`: returning `["_success": false, "_abortedByRequire": true, "_errorMessageFromRequire": error_message]`.
276
-
/// - in case of any error: returning `["_success": false, "_failureReason": String]`;
277
-
/// Error reasons include:
278
-
/// - `outputs` declared but at least one value failed to be decoded;
279
-
/// - `data.count` is less than `outputs.count * 32`;
NSLog("Function doesn't have any output types to decode given data.")
313
324
return["_success":true]
314
325
}
315
326
316
-
/// If data is empty and outputs are expected it is treated as a `requite(expression)` call with no message.
317
-
/// In solidity `require(expression)` call, if `expresison` returns `false`, results in an empty response.
318
-
if data.count ==0 && !outputs.isEmpty {
319
-
return["_success":false,"_failureReason":"Cannot decode empty data. \(outputs.count) outputs are expected: \(outputs.map{ $0.type.abiRepresentation }). Was this a result of en empty `require(expression)` call?"]
320
-
}
321
-
322
327
guard outputs.count *32<= data.count else{
323
328
return["_success":false,"_failureReason":"Bytes count must be at least \(outputs.count *32). Given \(data.count). Decoding will fail."]
/// Decodes `revert(string)`, `revert CustomError(...)` and `require(expression, string)` calls.
346
+
/// If `data` is empty and `outputs` are not empty it's considered that data is a result of `revert()` or `require(false)`.
347
+
/// - Parameters:
348
+
/// - data: returned function call data to decode;
349
+
/// - errors: optional known errors that could be thrown by the function you called.
350
+
/// - Returns: dictionary containing information about the error thrown by the function call.
351
+
///
352
+
/// What could be returned:
353
+
/// - `nil` if data doesn't represent an error or it failed to be mapped to any of the `errors` or `Error(string)` types;
354
+
/// - `nil` is `data.isEmpty` and `outputs.isEmpty`;
355
+
/// - `data.isEmpty` and `!outputs.isEmpty`:
356
+
/// ```swift
357
+
/// ["_success": false,
358
+
/// "_failureReason": "Cannot decode empty data. X outputs are expected: [outputs_types]. Was this a result of en empty `require(false)` or `revert()` call?"]
359
+
/// ```
360
+
/// - function call was aborted using `revert(message)` or `require(expression, message)`:
/// If data is empty and outputs are expected it is treated as a `require(expression)` or `revert()` call with no message.
386
+
/// In solidity `require(false)` and `revert()` calls return empty error response.
387
+
if data.isEmpty && !outputs.isEmpty {
388
+
return["_success":false,"_failureReason":"Cannot decode empty data. \(outputs.count) outputs are expected: \(outputs.map{ $0.type.abiRepresentation }). Was this a result of en empty `require(false)` or `revert()` call?"]
389
+
}
390
+
391
+
/// Explanation of this condition:
392
+
/// When `revert(string)` or `require(false, string)` are called in soliditiy they produce
393
+
/// an error, specifically an instance of default `Error(string)` type.
394
+
/// 1) The total number of bytes returned are at least 100.
395
+
/// 2) The function selector for `Error(string)` is `08C379A0`;
396
+
/// 3) Data offset must be present. Hexadecimal value of `0000...0020` is 32 in decimal. Reasoning for `BigInt(...) == 32`.
397
+
/// 4) `messageLength` is used to determine where message bytes end to decode string correctly.
398
+
/// 5) The rest of the `data` must be 0 bytes or empty.
399
+
if data.bytes.count >=100,
400
+
Data(data[0..<4])==Data.fromHex("08C379A0"),
401
+
BigInt(data[4..<36])==32,
402
+
let messageLength =Int(Data(data[36..<68]).toHexString(), radix:16),
403
+
let message =String(bytes: data.bytes[68..<(68+messageLength)], encoding:.utf8),
0 commit comments