From 04062d7219a1cd364661f8520bf18264aa4db5e3 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Mon, 16 Apr 2018 23:00:36 +0300 Subject: [PATCH 1/2] start implementing better types conversion for ABI encoding --- web3swift.podspec | 2 +- web3swift/ABIv2/Classes/ABIv2Encoding.swift | 109 ++++++++++++++++---- 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/web3swift.podspec b/web3swift.podspec index 212aef3..48985ec 100644 --- a/web3swift.podspec +++ b/web3swift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "web3swift" -s.version = "0.5.1" +s.version = "0.5.2" s.summary = "Web3 implementation in vanilla Swift for iOS ans macOS" s.description = <<-DESC diff --git a/web3swift/ABIv2/Classes/ABIv2Encoding.swift b/web3swift/ABIv2/Classes/ABIv2Encoding.swift index 0a354b6..1cfb73d 100644 --- a/web3swift/ABIv2/Classes/ABIv2Encoding.swift +++ b/web3swift/ABIv2/Classes/ABIv2Encoding.swift @@ -14,6 +14,91 @@ public struct ABIv2Encoder { } extension ABIv2Encoder { + public static func convertToBigUInt(_ value: AnyObject) -> BigUInt? { + switch value { + case let v as BigUInt: + return v + case let v as BigInt: + return v.magnitude + case let v as String: + let base10 = BigUInt(v, radix: 10) + if base10 != nil { + return base10! + } + let base16 = BigUInt(v.stripHexPrefix(), radix: 16) + if base16 != nil { + return base16! + } + break + case let v as UInt: + return BigUInt(v) + case let v as UInt8: + return BigUInt(v) + case let v as UInt16: + return BigUInt(v) + case let v as UInt32: + return BigUInt(v) + case let v as UInt64: + return BigUInt(v) + case let v as Int: + return BigUInt(v) + case let v as Int8: + return BigUInt(v) + case let v as Int16: + return BigUInt(v) + case let v as Int32: + return BigUInt(v) + case let v as Int64: + return BigUInt(v) + default: + return nil + } + return nil + } + + public static func convertToBigInt(_ value: AnyObject) -> BigInt? { + switch value { + case let v as BigUInt: + return BigInt(v) + case let v as BigInt: + return v + case let v as String: + let base10 = BigInt(v, radix: 10) + if base10 != nil { + return base10! + } + let base16 = BigInt(v.stripHexPrefix(), radix: 16) + if base16 != nil { + return base16! + } + break + case let v as UInt: + return BigInt(v) + case let v as UInt8: + return BigInt(v) + case let v as UInt16: + return BigInt(v) + case let v as UInt32: + return BigInt(v) + case let v as UInt64: + return BigInt(v) + case let v as Int: + return BigInt(v) + case let v as Int8: + return BigInt(v) + case let v as Int16: + return BigInt(v) + case let v as Int32: + return BigInt(v) + case let v as Int64: + return BigInt(v) + default: + return nil + } + return nil + } + + public static func encode(types: [ABIv2.Element.InOut], values: [AnyObject]) -> Data? { guard types.count == values.count else {return nil} let params = types.flatMap { (el) -> ABIv2.Element.ParameterType in @@ -63,33 +148,17 @@ extension ABIv2Encoder { public static func encodeSingleType(type: ABIv2.Element.ParameterType, value: AnyObject) -> Data? { switch type { case .uint(_): - if let biguint = value as? BigUInt { + if let biguint = convertToBigUInt(value) { return biguint.abiEncode(bits: 256) } - if let bigint = value as? BigInt { + if let bigint = convertToBigInt(value) { return bigint.abiEncode(bits: 256) } - if let num = value as? IntegerLiteralType { - let biguint = BigUInt(num) - return biguint.abiEncode(bits: 256) - } - if let numString = value as? String { - guard let biguint = BigUInt(numString, radix: 10) else {break} - return biguint.abiEncode(bits: 256) - } case .int(_): - if let biguint = value as? BigUInt { + if let biguint = convertToBigUInt(value) { return biguint.abiEncode(bits: 256) } - if let bigint = value as? BigInt { - return bigint.abiEncode(bits: 256) - } - if let num = value as? IntegerLiteralType { - let bigint = BigInt(num) - return bigint.abiEncode(bits: 256) - } - if let numString = value as? String { - guard let bigint = BigInt(numString, radix: 10) else {break} + if let bigint = convertToBigInt(value) { return bigint.abiEncode(bits: 256) } case .address: From 027f18bb5e6e48317598cda5da34794e9f3ea904 Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Mon, 16 Apr 2018 23:20:14 +0300 Subject: [PATCH 2/2] add more options for bytes and bytesX ABI initialization --- web3swift/ABIv2/Classes/ABIv2Encoding.swift | 96 +++++++++------------ 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/web3swift/ABIv2/Classes/ABIv2Encoding.swift b/web3swift/ABIv2/Classes/ABIv2Encoding.swift index 1cfb73d..212c8d9 100644 --- a/web3swift/ABIv2/Classes/ABIv2Encoding.swift +++ b/web3swift/ABIv2/Classes/ABIv2Encoding.swift @@ -65,11 +65,11 @@ extension ABIv2Encoder { case let v as String: let base10 = BigInt(v, radix: 10) if base10 != nil { - return base10! + return base10 } let base16 = BigInt(v.stripHexPrefix(), radix: 16) if base16 != nil { - return base16! + return base16 } break case let v as UInt: @@ -98,6 +98,36 @@ extension ABIv2Encoder { return nil } + public static func convertToData(_ value: AnyObject) -> Data? { + switch value { + case let d as Data: + return d + case let d as String: + let hex = Data.fromHex(d.stripHexPrefix()) + if hex != nil { + return hex + } + let str = d.data(using: .utf8) + if str != nil { + return str + } + case let d as [UInt8]: + return Data(d) + case let d as EthereumAddress: + return d.addressData + case let d as [IntegerLiteralType]: + var bytesArray = [UInt8]() + for el in d { + guard el >= 0, el <= 255 else {return nil} + bytesArray.append(UInt8(el)) + } + return Data(bytesArray) + default: + return nil + } + return nil + } + public static func encode(types: [ABIv2.Element.InOut], values: [AnyObject]) -> Data? { guard types.count == values.count else {return nil} @@ -183,27 +213,9 @@ extension ABIv2Encoder { } } case .bytes(let length): - if let string = value as? String { - var dataGuess: Data? - if string.hasHexPrefix() { - dataGuess = Data.fromHex(string.lowercased().stripHexPrefix()) - } - else { - dataGuess = string.data(using: .utf8) - } - guard let data = dataGuess else {break} - if data.count > length {break} - return data.setLengthRight(32) - } else if let addr = value as? EthereumAddress { - guard addr.isValid else {break} - let data = addr.addressData - return data.setLengthRight(32) - } else if let data = value as? Data { - return data.setLengthRight(32) - } else if let byteArray = value as? [UInt8] { - let data = Data(byteArray) - return data.setLengthRight(32) - } + guard let data = convertToData(value) else {break} + if data.count > length {break} + return data.setLengthRight(32) case .string: if let string = value as? String { var dataGuess: Data? @@ -222,37 +234,13 @@ extension ABIv2Encoder { return total } case .dynamicBytes: - if let string = value as? String { - var dataGuess: Data? - if string.hasHexPrefix() { - dataGuess = Data.fromHex(string.lowercased().stripHexPrefix()) - } - else { - dataGuess = string.data(using: .utf8) - } - guard let data = dataGuess else {break} - let minLength = ((data.count + 31) / 32)*32 - guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break} - let length = BigUInt(data.count) - guard let head = length.abiEncode(bits: 256) else {break} - let total = head+paddedData - return total - } else if let data = value as? Data { - let minLength = ((data.count + 31) / 32)*32 - guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break} - let length = BigUInt(data.count) - guard let head = length.abiEncode(bits: 256) else {break} - let total = head+paddedData - return total - } else if let byteArray = value as? [UInt8] { - let data = Data(byteArray) - let minLength = ((data.count + 31) / 32)*32 - guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break} - let length = BigUInt(data.count) - guard let head = length.abiEncode(bits: 256) else {break} - let total = head+paddedData - return total - } + guard let data = convertToData(value) else {break} + let minLength = ((data.count + 31) / 32)*32 + guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break} + let length = BigUInt(data.count) + guard let head = length.abiEncode(bits: 256) else {break} + let total = head+paddedData + return total case .array(type: let subType, length: let length): switch type.arraySize { case .dynamicSize: