Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small fixes. #11

Merged
merged 7 commits into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,8 @@ fastlane/test_output
# Xcodeproj generated with `swift package generate-xcodeproj`.
# Can be safely ignored and recreated, as it's only used for development.
Bivrost.xcodeproj

# Local test data should not be committed.
testcontracts
testoutput

2 changes: 1 addition & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ opt_in_rules: # some rules are only opt-in
# Make certain rules give out an error
force_cast: error
force_try: error
force_unwrapping: error
force_unwrapping: warning
10 changes: 5 additions & 5 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
},
{
"package": "CryptoSwift",
"repositoryURL": "https://github.com/zweigraf/CryptoSwift.git",
"repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift",
"state": {
"branch": null,
"revision": "fdd115318528c9c25a06c0a89553f71bde7233da",
"version": null
"revision": "d0084e4a6fe9490b3baab3d3c2aad58d3a852daf",
"version": "0.8.0"
}
},
{
Expand All @@ -51,8 +51,8 @@
"repositoryURL": "https://github.com/Quick/Quick.git",
"state": {
"branch": null,
"revision": "c498edf4aabb694a5b8a861ec3d69f0c5ab57d9e",
"version": null
"revision": "0ff81f2c665b4381f526bd656f8708dd52a9ea2f",
"version": "1.2.0"
}
},
{
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/krzyzanowskim/CryptoSwift", .upToNextMinor(from: "0.8.0")),
.package(url: "https://github.com/attaswift/BigInt.git", .upToNextMajor(from: "3.0.0")),
.package(url: "https://github.com/Quick/Nimble.git", .upToNextMajor(from: "7.0.2")),
.package(url: "https://github.com/Quick/Quick.git", .revision("c498edf4aabb694a5b8a861ec3d69f0c5ab57d9e")),
.package(url: "https://github.com/Quick/Nimble.git", .upToNextMinor(from: "7.0.2")),
.package(url: "https://github.com/Quick/Quick.git", .upToNextMinor(from: "1.2.0")),
.package(url: "https://github.com/kylef/Commander.git", .revision("e0cbee1bd73778c1076c675eaf660e97d09f3b32")),
// PathKit fork supporting SPM4
.package(url: "https://github.com/PoissonBallon/PathKit.git", .branch("master")),
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

🔥 🌈 Bridge between Solidity Contracts and Swift

[![CI Status](http://img.shields.io/travis/gnosis/bivrost-swift.svg?style=flat)](https://travis-ci.org/gnosis/bivrost-swift)

Bivrost is in very early development. Do not use this for anything important.

## Description
Expand Down Expand Up @@ -116,4 +114,8 @@ Bivrost is available under the MIT license. See the LICENSE file for more info.

## Issues

Tests currently do not work when generating an Xcode project via `swift package generate-xcodeproj`. This issue is described at the bottom of <https://github.com/Quick/Quick/issues/707>. Drop to the CMD and use `swift test` for testing.
Tests currently do not work when generating an Xcode project via `swift package generate-xcodeproj`. This issue is described in <https://github.com/Quick/Quick/issues/751>.

Workarounds:
- Drop to the CMD and use `swift test` for testing.
- Go to the `QuickSpecBase` target build settings in the generated Xcode project. Set `Enables Module` to `YES` (`CLANG_ENABLE_MODULES=YES`). Now testing should work.
2 changes: 2 additions & 0 deletions Resources/BivrostError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Foundation

enum BivrostError: Error {
enum Decoder: Error {
case endOfSourceData

// Decoding
case invalidBool(hex: String)
case invalidUInt(hex: String)
Expand Down
11 changes: 7 additions & 4 deletions Resources/Coding/BaseDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ struct BaseDecoder {
}

static func decodeBytes(source: PartitionData) throws -> Data {
let sizePart = source.consume()
let sizePart = try source.consume()
guard let size = Int(sizePart, radix: 16) else {
throw BivrostError.Decoder.invalidBytesLength(hex: sizePart)
}

var byteHolder = Data()
while byteHolder.count < size {
if let data = Data(fromHexEncodedString: source.consume()) {
if let data = Data(fromHexEncodedString: try source.consume()) {
byteHolder.append(data)
}
}
Expand Down Expand Up @@ -107,7 +107,7 @@ struct BaseDecoder {
}
// We have dynamic types, we need to check the dynamic array
// Consume all locations to jump cursor ahead to dynamic section
(0..<capacity).forEach { _ in _ = source.consume() }
try (0..<capacity).forEach { _ in _ = try source.consume() }
return try (0..<capacity).map { _ in try decoder(source) }
}
}
Expand All @@ -126,7 +126,10 @@ extension BaseDecoder {

var index: Int = 0

func consume() -> String {
func consume() throws -> String {
guard index < lines.count else {
throw BivrostError.Decoder.endOfSourceData
}
let returnValue = lines[index]
index += 1
return returnValue
Expand Down
10 changes: 10 additions & 0 deletions Resources/Extensions/StringExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,13 @@ extension String {
return forBytes * 2
}
}

// MARK: - Hex Helper
extension String {
/// Returns a new string, removing a '0x' prefix if present.
var withoutHexPrefix: String {
return hasPrefix("0x")
? String(dropFirst(2))
: self
}
}
4 changes: 1 addition & 3 deletions Resources/Types/Address.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ public extension Solidity {
private let bigInt: BigUInt

init(_ address: Swift.String) throws {
let hex = address.hasPrefix("0x")
? Swift.String(address[address.index(address.startIndex, offsetBy: 2)...])
: address
let hex = address.withoutHexPrefix
guard let bigInt = BigUInt(hex, radix: 16) else {
throw BivrostError.Address.invalidAddress(hex)
}
Expand Down
2 changes: 1 addition & 1 deletion Resources/Types/ArrayX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
extension _DoNotUse {
// swiftlint:disable:next type_name
class _ArrayX<T: SolidityCodable & Equatable> {
private let items: [T]
let items: [T]
class var length: UInt {
fatalError("Not meant to be called directly.")
}
Expand Down
6 changes: 6 additions & 0 deletions Resources/Types/Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ import BigInt

public extension Solidity {
struct Bool {
private let value: Swift.Bool
private let wrapper: UInt8

init(_ value: Swift.Bool) {
self.value = value
guard let wrapper = try? UInt8(BigUInt(value ? 1 : 0)) else {
fatalError("Solidity.Bool could not be created with value of \(value). This should not happen.")
}
self.wrapper = wrapper
}

func unwrap() -> Swift.Bool {
return value
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Resources/Types/Bytes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public extension Solidity {
self.value = value
self.length = length
}

func unwrap() -> Data {
return value
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Resources/Types/BytesX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public extension _DoNotUse {
}
self.value = value
}

func unwrap() -> Data {
return value
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Resources/Types/Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension Solidity.Function: StaticType {
}

static func decode(source: BaseDecoder.PartitionData) throws -> Solidity.Function {
let line = source.consume()
let line = try source.consume()
// 20 bytes / 40 chars for Address as UInt160
let addressHex = String(line[line.startIndex ..< line.index(startDistance: 40)])
let uint = try BaseDecoder.decodeUInt(data: addressHex)
Expand Down
4 changes: 4 additions & 0 deletions Resources/Types/IntX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public extension _DoNotUse {
}
value = int
}

func unwrap() -> BigInt {
return value
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions Resources/Types/String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@
public extension Solidity {
struct String {
let wrapper: Solidity.Bytes
let value: Swift.String

init?(_ value: Swift.String) {
self.value = value

guard let data = value.data(using: .utf8),
let bytes = Solidity.Bytes(data) else {
return nil
}
self.wrapper = bytes
}

func unwrap() -> Swift.String {
return value
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions Resources/Types/UIntX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public extension _DoNotUse {
}
value = uint
}

func unwrap() -> BigUInt {
return value
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Resources/Types/VariableArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ extension Solidity {
// MARK: - DynamicType
extension Solidity.VariableArray: DynamicType {
static func decode(source: BaseDecoder.PartitionData) throws -> Solidity.VariableArray<T> {
let sizePart = source.consume()
let sizePart = try source.consume()
guard let size = UInt(sizePart, radix: 16) else {
throw BivrostError.Decoder.invalidArrayLength(hex: sizePart)
}
Expand Down
8 changes: 7 additions & 1 deletion Sources/BivrostKit/Generating/ContractTemplateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ struct ContractTemplateModel {

let decodeReturnReturnValue: String // Name to be returned at the end of decode(returnData:)
let decodeReturnTypes: [DecodeType]
let hasEmptyDecodeReturnFunction: Bool

let decodeArgumentsReturnValue: String // Name to be returned at the end of decode(argumentsData:)
let decodeArgumentsTypes: [DecodeType]
let hasEmptyDecodeArgumentsFunction: Bool

struct DecodeType {
let name: String
Expand Down Expand Up @@ -61,12 +63,16 @@ struct ContractTemplateModel {
let outputString = tupleString(for: object.outputs)

let encodeArgumentsString = encodeArguments(for: object.inputs)

let decodeReturnTypesArray = decodeTypes(for: object.outputs)
let hasEmptyDecodeReturnFunction = decodeReturnTypesArray.isEmpty
let decodeReturnReturnValueString = decodeReturnReturnValue(for: decodeReturnTypesArray)

let decodeArgumentsTypesArray = decodeTypes(for: object.inputs)
let hasEmptyDecodeArgumentsFunction = decodeArgumentsTypesArray.isEmpty
let decodeArgumentsReturnValueString = decodeArgumentsReturnValue(for: decodeArgumentsTypesArray)

return ContractTemplateModel.Function(name: preparedFunctionName, methodId: functionMethodId, input: inputString, output: outputString, encodeArguments: encodeArgumentsString, decodeReturnReturnValue: decodeReturnReturnValueString, decodeReturnTypes: decodeReturnTypesArray, decodeArgumentsReturnValue: decodeArgumentsReturnValueString, decodeArgumentsTypes: decodeArgumentsTypesArray)
return ContractTemplateModel.Function(name: preparedFunctionName, methodId: functionMethodId, input: inputString, output: outputString, encodeArguments: encodeArgumentsString, decodeReturnReturnValue: decodeReturnReturnValueString, decodeReturnTypes: decodeReturnTypesArray, hasEmptyDecodeReturnFunction: hasEmptyDecodeReturnFunction, decodeArgumentsReturnValue: decodeArgumentsReturnValueString, decodeArgumentsTypes: decodeArgumentsTypesArray, hasEmptyDecodeArgumentsFunction: hasEmptyDecodeArgumentsFunction)
}
}
}
Expand Down
31 changes: 20 additions & 11 deletions Sources/BivrostKit/Generating/Templates/ContractTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,63 @@ extension Templates {

struct {{ contract.name }} {
{% for function in contract.functions %}

struct {{ function.name }}: SolidityFunction {
static let methodId = "{{ function.methodId }}"
typealias Return = {{ function.output }}
typealias Arguments = {{ function.input }}

static func encodeCall(arguments: Arguments) -> String {
return "0x\\(methodId)\\(BaseEncoder.encode(arguments: {{ function.encodeArguments }}))"
}


{% if function.hasEmptyDecodeReturnFunction %}
static func decode(returnData: String) throws -> Return {}
{% else %}
static func decode(returnData: String) throws -> Return {
let source = BaseDecoder.partition(returnData)
// Static Types & Location
// Decode Static Types & Locations for Dynamic Types
{% for decodedType in function.decodeReturnTypes %}
{% if decodedType.isDynamic %}
// Ignore location for dynamic type
_ = source.consume()
// Ignore location for {{ decodedType.name }} (dynamic type)
_ = try source.consume()
{% else %}
let {{ decodedType.name }} = try {{ decodedType.type }}.decode(source: source)
{% endif %}
{% endfor %}
// Dynamic Types
// Dynamic Types (if any)
{% for decodedType in function.decodeReturnTypes %}
{% if decodedType.isDynamic %}
let {{ decodedType.name }} = try {{ decodedType.type }}.decode(source: source)
{% endif %}
{% endfor %}
return {{ function.decodeReturnReturnValue }}
}

{% endif %}

{% if function.hasEmptyDecodeArgumentsFunction %}
static func decode(argumentsData: String) throws -> Arguments {}
{% else %}
static func decode(argumentsData: String) throws -> Arguments {
let source = BaseDecoder.partition(argumentsData)
// Static Types & Location
// Decode Static Types & Locations for Dynamic Types
{% for decodedType in function.decodeArgumentsTypes %}
{% if decodedType.isDynamic %}
// Ignore location for dynamic type
_ = source.consume()
// Ignore location for {{ decodedType.name }} (dynamic type)
_ = try source.consume()
{% else %}
let {{ decodedType.name }} = try {{ decodedType.type }}.decode(source: source)
{% endif %}
{% endfor %}
// Dynamic Types
// Dynamic Types (if any)
{% for decodedType in function.decodeArgumentsTypes %}
{% if decodedType.isDynamic %}
let {{ decodedType.name }} = try {{ decodedType.type }}.decode(source: source)
{% endif %}
{% endfor %}
return {{ function.decodeArgumentsReturnValue }}
}
{% endif %}
}
{% endfor %}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/BivrostKit/Parsing/ContractParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct ContractParser {
/// - Throws: Throws if the json was malformed, e.g. a required field was missing.
static func parseContract(from json: [String: Any]) throws -> Contract {
guard let name = json[.contractName] as? String else {
throw ParsingError.contractNameInvalid
throw ParsingError.contractNameInvalid(json: json)
}
guard let elementsJson = json[.abi] as? [[String: Any]] else {
throw ParsingError.contractAbiInvalid
Expand Down
2 changes: 1 addition & 1 deletion Sources/BivrostKit/Parsing/ParsingError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ enum ParsingError: Error {
case eventInputInvalid
case parameterTypeInvalid
case parameterTypeNotFound
case contractNameInvalid
case contractNameInvalid(json: [String: Any])
case contractAbiInvalid
}