Skip to content
This repository has been archived by the owner on Sep 13, 2024. It is now read-only.

Commit

Permalink
Merge pull request #41 from BANKEX/develop
Browse files Browse the repository at this point in the history
ABIv2 encoder now also works. Tested for most of the types, including string[2] and string[]
  • Loading branch information
shamatar authored Apr 7, 2018
2 parents d0f3cca + ec77dcd commit 05bf345
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 117 deletions.
1 change: 0 additions & 1 deletion web3swift/ABIv2/Classes/ABIv2Decoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ extension ABIv2Decoder {
indexedValues.append(valueUnwrapped)
}
}
// let (v, _) = ABIv2Decoder.decodeTypesTuple(tuple: ABIv2.Element.ParameterType.tuple(types: nonIndexedTypes), data: dataForProcessing)
let v = ABIv2Decoder.decode(types: nonIndexedTypes, data: dataForProcessing)
guard let nonIndexedValues = v else {return nil}
var indexedInputCounter = 0
Expand Down
4 changes: 0 additions & 4 deletions web3swift/ABIv2/Classes/ABIv2Elements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@ extension ABIv2 {
var components: [Input]?
}

// public struct InputComponent: Decodable {
//
// }

public struct Output: Decodable {
var name: String?
var type: String
Expand Down
270 changes: 181 additions & 89 deletions web3swift/ABIv2/Classes/ABIv2Encoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,85 @@ extension ABIv2Encoder {
let params = types.flatMap { (el) -> ABIv2.Element.ParameterType in
return el.type
}
let tuple = ABIv2.Element.ParameterType.tuple(types: params)
let (h, t, _) = encodeTypesTuple(tuple: tuple, values: values)
guard let head = h, let tail = t else {return nil}
return head + tail
return encode(types: params, values: values)
}

public static func encodeSingleType(type: ABIv2.Element.ParameterType, value: AnyObject, pointer: BigUInt = BigUInt(0)) -> (head: Data?, tail: Data?, pointer: BigUInt?) {
public static func encode(types: [ABIv2.Element.ParameterType], values: [AnyObject]) -> Data? {
guard types.count == values.count else {return nil}
var tails = [Data]()
var heads = [Data]()
for i in 0 ..< types.count {
let enc = encodeSingleType(type: types[i], value: values[i])
guard let encoding = enc else {return nil}
if types[i].isStatic {
heads.append(encoding)
tails.append(Data())
} else {
heads.append(Data(repeating: 0x0, count: 32))
tails.append(encoding)
}
}
var headsConcatenated = Data()
for h in heads {
headsConcatenated.append(h)
}
var tailsPointer = BigUInt(headsConcatenated.count)
headsConcatenated = Data()
var tailsConcatenated = Data()
for i in 0 ..< types.count {
let head = heads[i]
let tail = tails[i]
print(types[i])
print(head.toHexString())
print(tail.toHexString())
if !types[i].isStatic {
guard let newHead = tailsPointer.abiEncode(bits: 256) else {return nil}
headsConcatenated.append(newHead)
tailsConcatenated.append(tail)
tailsPointer = tailsPointer + BigUInt(tail.count)
} else {
headsConcatenated.append(head)
tailsConcatenated.append(tail)
}
}
return headsConcatenated + tailsConcatenated
}

public static func encodeSingleType(type: ABIv2.Element.ParameterType, value: AnyObject) -> Data? {
switch type {
case .uint(_):
if let biguint = value as? BigUInt {
return (biguint.abiEncode(bits: 256), Data(), pointer)
return biguint.abiEncode(bits: 256)
}
if let bigint = value as? BigInt {
return (bigint.abiEncode(bits: 256), Data(), pointer)
return bigint.abiEncode(bits: 256)
}
case .int(_):
if let biguint = value as? BigUInt {
return (biguint.abiEncode(bits: 256), Data(), pointer)
return biguint.abiEncode(bits: 256)
}
if let bigint = value as? BigInt {
return (bigint.abiEncode(bits: 256), Data(), pointer)
return bigint.abiEncode(bits: 256)
}
case .address:
if let string = value as? String {
let address = EthereumAddress(string)
guard address.isValid else {break}
let data = address.addressData
return (data.setLengthLeft(32), Data(), pointer)
return data.setLengthLeft(32)
} else if let address = value as? EthereumAddress {
guard address.isValid else {break}
let data = address.addressData
return (data.setLengthLeft(32), Data(), pointer)
return data.setLengthLeft(32)
} else if let data = value as? Data {
return (data.setLengthLeft(32), Data(), pointer)
return data.setLengthLeft(32)
}
case .bool:
if let bool = value as? Bool {
if (bool) {
return (BigUInt(1).abiEncode(bits: 256), Data(), pointer)
return BigUInt(1).abiEncode(bits: 256)
} else {
return (BigUInt(0).abiEncode(bits: 256), Data(), pointer)
return BigUInt(0).abiEncode(bits: 256)
}
}
case .bytes(let length):
Expand All @@ -73,13 +111,13 @@ extension ABIv2Encoder {
}
guard let data = dataGuess else {break}
if data.count > length {break}
return (data.setLengthRight(32), Data(), pointer)
return data.setLengthRight(32)
} else if let addr = value as? EthereumAddress {
guard addr.isValid else {break}
let data = addr.addressData
return (data.setLengthRight(32), Data(), pointer)
return data.setLengthRight(32)
} else if let data = value as? Data {
return (data.setLengthRight(32), Data(), pointer)
return data.setLengthRight(32)
}
case .string:
if let string = value as? String {
Expand All @@ -95,8 +133,8 @@ extension ABIv2Encoder {
guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break}
let length = BigUInt(data.count)
guard let head = length.abiEncode(bits: 256) else {break}
let tail = head+paddedData
return (Data(), tail, pointer + BigUInt(tail.count))
let total = head+paddedData
return total
}
case .dynamicBytes:
if let string = value as? String {
Expand All @@ -112,101 +150,155 @@ extension ABIv2Encoder {
guard let paddedData = data.setLengthRight(UInt64(minLength)) else {break}
let length = BigUInt(data.count)
guard let head = length.abiEncode(bits: 256) else {break}
let tail = head+paddedData
return (Data(), tail, pointer + BigUInt(tail.count))
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 tail = head+paddedData
return (Data(), tail, pointer + BigUInt(tail.count))
let total = head+paddedData
return total
}
case .array(type: let subType, length: let length):
switch type.arraySize {
case .dynamicSize:
guard length == 0 else {break}
guard let val = value as? [AnyObject] else {break}
var tails = Data()
for i in 0 ..< val.count {
let (h, t, p) = encodeSingleType(type: subType, value: val[i], pointer: pointer)
guard let headUnwrapped = h, let tailUnwrapped = t, let _ = p else {break}
guard headUnwrapped != Data() else {break}
guard tailUnwrapped == Data() else {break}
tails.append(headUnwrapped)
guard let lengthEncoding = BigUInt(val.count).abiEncode(bits: 256) else {break}
if subType.isStatic {
// work in a previous context
var toReturn = Data()
for i in 0 ..< val.count {
let enc = encodeSingleType(type: subType, value: val[i])
guard let encoding = enc else {break}
toReturn.append(encoding)
}
let total = lengthEncoding + toReturn
print("Dynamic array of static types encoding :\n" + String(total.toHexString()))
return total
} else {
// create new context
var tails = [Data]()
var heads = [Data]()
for i in 0 ..< val.count {
let enc = encodeSingleType(type: subType, value: val[i])
guard let encoding = enc else {return nil}
heads.append(Data(repeating: 0x0, count: 32))
tails.append(encoding)
}
var headsConcatenated = Data()
for h in heads {
headsConcatenated.append(h)
}
var tailsPointer = BigUInt(headsConcatenated.count)
headsConcatenated = Data()
var tailsConcatenated = Data()
for i in 0 ..< val.count {
let head = heads[i]
let tail = tails[i]
if tail != Data() {
guard let newHead = tailsPointer.abiEncode(bits: 256) else {return nil}
headsConcatenated.append(newHead)
tailsConcatenated.append(tail)
tailsPointer = tailsPointer + BigUInt(tail.count)
} else {
headsConcatenated.append(head)
tailsConcatenated.append(tail)
}
}
let total = lengthEncoding + headsConcatenated + tailsConcatenated
print("Dynamic array of dynamic types encoding :\n" + String(total.toHexString()))
return total
}
guard let prefix = BigUInt(val.count).abiEncode(bits: 256) else {break}
tails = prefix + tails
return (pointer.abiEncode(bits: 256)!, tails, pointer + BigUInt(tails.count))
case .staticSize(let staticLength):
guard length == staticLength else {break}
guard staticLength != 0 else {break}
guard let val = value as? [AnyObject] else {break}
guard staticLength == val.count else {break}
let types = [ABIv2.Element.ParameterType](repeating: subType, count: val.count)
let tuple = ABIv2.Element.ParameterType.tuple(types: types)
return encodeTypesTuple(tuple: tuple, values: val, pointer: pointer)
if subType.isStatic {
// work in a previous context
var toReturn = Data()
for i in 0 ..< val.count {
let enc = encodeSingleType(type: subType, value: val[i])
guard let encoding = enc else {break}
toReturn.append(encoding)
}
print("Static array of static types encoding :\n" + String(toReturn.toHexString()))
let total = toReturn
return total
} else {
// create new context
var tails = [Data]()
var heads = [Data]()
for i in 0 ..< val.count {
let enc = encodeSingleType(type: subType, value: val[i])
guard let encoding = enc else {return nil}
heads.append(Data(repeating: 0x0, count: 32))
tails.append(encoding)
}
var headsConcatenated = Data()
for h in heads {
headsConcatenated.append(h)
}
var tailsPointer = BigUInt(headsConcatenated.count)
headsConcatenated = Data()
var tailsConcatenated = Data()
for i in 0 ..< val.count {
let tail = tails[i]
guard let newHead = tailsPointer.abiEncode(bits: 256) else {return nil}
headsConcatenated.append(newHead)
tailsConcatenated.append(tail)
tailsPointer = tailsPointer + BigUInt(tail.count)
}
let total = headsConcatenated + tailsConcatenated
print("Static array of dynamic types encoding :\n" + String(total.toHexString()))
return total
}
case .notArray:
break
}
case .tuple(types: let subTypes):
var tails = [Data]()
var heads = [Data]()
guard let val = value as? [AnyObject] else {break}
guard subTypes.count == val.count else {break}
let tuple = ABIv2.Element.ParameterType.tuple(types: subTypes)
return encodeTypesTuple(tuple: tuple, values: val, pointer: pointer)
case .function:
if let data = value as? Data {
return (data.setLengthLeft(32), Data(), pointer)
}
}
return (nil, nil, nil)
}

public static func encodeTypesTuple(tuple: ABIv2.Element.ParameterType, values: [AnyObject], pointer: BigUInt = BigUInt(0)) -> (head: Data?, tail: Data?, pointer: BigUInt?) {
guard case .tuple(types: let types) = tuple else {return (nil, nil, nil)}
let memoryUsage = tuple.memoryUsage
var offset: BigUInt = BigUInt(memoryUsage);
if pointer != BigUInt(0) {
offset = pointer
}
guard types.count == values.count else {return (nil, nil, nil)}
var head = Data()
var tail = Data()
var h, t : Data?
var p: BigUInt?
if tuple.isStatic {
for i in 0 ..< types.count {
if let val = values[i] as? AnyObject {
(h, t, p) = encodeSingleType(type: types[i], value: val, pointer: offset)
} else {
return (nil, nil, nil)
}
guard let headUnwrapped = h, let tailUnwrapped = t, let pointerUnwrapped = p else {return (nil, nil, nil)}
guard headUnwrapped != Data() else {return (nil, nil, nil)}
head.append(headUnwrapped)
offset = pointerUnwrapped
}
} else {
for i in 0 ..< types.count {
if let val = values[i] as? AnyObject {
(h, t, p) = encodeSingleType(type: types[i], value: val, pointer: offset)
for i in 0 ..< subTypes.count {
let enc = encodeSingleType(type: subTypes[i], value: val[i])
guard let encoding = enc else {return nil}
if subTypes[i].isStatic {
heads.append(encoding)
tails.append(Data())
} else {
return (nil, nil, nil)
heads.append(Data(repeating: 0x0, count: 32))
tails.append(encoding)
}
guard let headUnwrapped = h, let tailUnwrapped = t, let pointerUnwrapped = p else {return (nil, nil, nil)}
if headUnwrapped != Data() {
head.append(headUnwrapped)
tail.append(tailUnwrapped)
offset = pointerUnwrapped
}
var headsConcatenated = Data()
for h in heads {
headsConcatenated.append(h)
}
var tailsPointer = BigUInt(headsConcatenated.count)
headsConcatenated = Data()
var tailsConcatenated = Data()
for i in 0 ..< subTypes.count {
let head = heads[i]
let tail = tails[i]
if !subTypes[i].isStatic {
guard let newHead = tailsPointer.abiEncode(bits: 256) else {return nil}
headsConcatenated.append(newHead)
tailsConcatenated.append(tail)
tailsPointer = tailsPointer + BigUInt(tail.count)
} else {
guard let pointerEncoded = offset.abiEncode(bits: 256) else {return (nil, nil, nil)}
head.append(pointerEncoded)
offset = pointerUnwrapped
tail.append(tailUnwrapped)
headsConcatenated.append(head)
tailsConcatenated.append(tail)
}
print(offset)
}
let total = headsConcatenated + tailsConcatenated
return total
case .function:
if let data = value as? Data {
return data.setLengthLeft(32)
}
}
return (head, tail, offset)
return nil
}

}
5 changes: 2 additions & 3 deletions web3swift/ABIv2/Classes/ABIv2ParameterTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ extension ABIv2.Element {

var isStatic: Bool {
switch self {
case .bytes:
return false
case .string:
return false
case .dynamicBytes:
Expand All @@ -47,12 +45,13 @@ extension ABIv2.Element {
}
}
return true
case .bytes(length: _):
return true
default:
return true
}
}


var isArray: Bool {
switch self {
case .array(type: _, length: _):
Expand Down
Loading

0 comments on commit 05bf345

Please sign in to comment.