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

Contract deployment implementation #48

Merged
merged 5 commits into from
Apr 11, 2018
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
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,9 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 62V9CKQN89;
DEVELOPMENT_TEAM = 5UH69GW6GE;
INFOPLIST_FILE = web3swiftExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.bankexfoundation.web3swiftExample;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -373,8 +374,9 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 62V9CKQN89;
DEVELOPMENT_TEAM = 5UH69GW6GE;
INFOPLIST_FILE = web3swiftExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = org.bankexfoundation.web3swiftExample;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
176 changes: 176 additions & 0 deletions web3swift/ABI/Classes/RLP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,182 @@ struct RLP {
}
return encodedLength
}

static func decode(_ raw: String) -> RLPItem? {
guard let rawData = Data.fromHex(raw) else {return nil}
return decode(rawData)
}

static func decode(_ raw: Data) -> RLPItem? {
if raw.count == 0 {
return RLPItem.noItem
}
var outputArray = [RLPItem]()
var bytesToParse = raw
while bytesToParse.count != 0 {
let (of, dl, t) = decodeLength(bytesToParse)
guard let offset = of, let dataLength = dl, let type = t else {return nil}
switch type {
case .empty:
break
case .data:
guard let slice = try? slice(data: bytesToParse, offset: offset, length: dataLength) else {return nil}
let data = Data(slice)
let rlpItem = RLPItem.init(content: .data(data))
outputArray.append(rlpItem)
case .list:
guard let slice = try? slice(data: bytesToParse, offset: offset, length: dataLength) else {return nil}
guard let inside = decode(Data(slice)) else {return nil}
switch inside.content {
case .data(_):
return nil
default:
outputArray.append(inside)
}
}
guard let tail = try? slice(data: bytesToParse, start: offset + dataLength) else {return nil}
bytesToParse = tail
}
return RLPItem.init(content: .list(outputArray, 0))
}

enum UnderlyingType {
case empty
case data
case list
}

struct RLPItem {

enum RLPContent {
case noItem
case data(Data)
indirect case list([RLPItem], Int)
}

var content: RLPContent

var isData: Bool {
switch self.content {
case .noItem:
return false
case .data(_):
return true
case .list(_):
return false
}
}

var isList: Bool {
switch self.content {
case .noItem:
return false
case .data(_):
return false
case .list(_):
return true
}
}
var count: Int? {
switch self.content {
case .noItem:
return nil
case .data(_):
return nil
case .list(let list, _):
return list.count
}
}
var hasNext: Bool {
switch self.content {
case .noItem:
return false
case .data(_):
return false
case .list(let list, let counter):
return list.count > counter
}
}

subscript(index: Int) -> RLPItem? {
get {
guard self.hasNext else {return nil}
guard case .list(let list, _) = self.content else {return nil}
let item = list[index]
return item
}
}

var data: Data? {
return self.getData()
}

func getData() -> Data? {
if self.isList {
return nil
}
guard case .data(let data) = self.content else {return nil}
return data
}

static var noItem: RLPItem {
return RLPItem.init(content: .noItem)
}
}

internal static func decodeLength(_ input: Data) -> (offset: BigUInt?, length: BigUInt?, type: UnderlyingType?) {
do {
let length = BigUInt(input.count)
if (length == BigUInt(0)) {
return (0, 0, .empty)
}
let prefixByte = input[0]
if prefixByte <= 0x7f {
return (BigUInt(0), BigUInt(1), .data)
}else if prefixByte <= 0xb7 && length > BigUInt(prefixByte - 0x80) {
let dataLength = BigUInt(prefixByte - 0x80)
return (BigUInt(1), dataLength, .data)
} else if try prefixByte <= 0xbf && length > BigUInt(prefixByte - 0xb7) && length > BigUInt(prefixByte - 0xb7) + toBigUInt(slice(data: input, offset: BigUInt(1), length: BigUInt(prefixByte - 0xb7))) {
let lengthOfLength = BigUInt(prefixByte - 0xb7)
let dataLength = try toBigUInt(slice(data: input, offset: BigUInt(1), length: BigUInt(prefixByte - 0xb7)))
return (1 + lengthOfLength, dataLength, .data)
} else if prefixByte <= 0xf7 && length > BigUInt(prefixByte - 0xc0) {
let listLen = BigUInt(prefixByte - 0xc0)
return (1, listLen, .list)
} else if try prefixByte <= 0xff && length > BigUInt(prefixByte - 0xf7) && length > BigUInt(prefixByte - 0xf7) + toBigUInt(slice(data: input, offset: BigUInt(1), length: BigUInt(prefixByte - 0xf7))) {
let lengthOfListLength = BigUInt(prefixByte - 0xf7)
let listLength = try toBigUInt(slice(data: input, offset: BigUInt(1), length: BigUInt(prefixByte - 0xf7)))
return (1 + lengthOfListLength, listLength, .list)
} else {
return (nil, nil, nil)
}
} catch {
return (nil, nil, nil)
}
}

internal static func slice(data: Data, offset: BigUInt, length: BigUInt) throws -> Data {
if BigUInt(data.count) < offset + length {throw Web3Error.dataError}
let slice = data[UInt64(offset) ..< UInt64(offset + length)]
return Data(slice)
}

internal static func slice(data: Data, start: BigUInt) throws -> Data {
if BigUInt(data.count) < start {throw Web3Error.dataError}
let slice = data[UInt64(start) ..< UInt64(data.count)]
return Data(slice)
}

internal static func toBigUInt(_ raw: Data) throws -> BigUInt {
if raw.count == 0 {
throw Web3Error.dataError
} else if raw.count == 1 {
return BigUInt.init(raw)
} else {
let slice = raw[0 ..< raw.count - 1]
return try BigUInt(raw[raw.count-1]) + toBigUInt(slice)*256
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ final class ContractSendOperation: Web3Operation {
}
transaction.nonce = nonce
intermediate.transaction = transaction
intermediate.options = options
guard let gasEstimateOperation = ContractEstimateGasOperation.init(self.web3, queue: self.expectedQueue, intermediate: intermediate, onBlock: onBlock) else {return self.processError(Web3Error.dataError)}
gasEstimateOperation.next = OperationChainingType.callback(gasEstimationCallback, self.expectedQueue)
self.expectedQueue.addOperation(gasEstimateOperation)
Expand Down
13 changes: 5 additions & 8 deletions web3swift/Contract/Classes/Contract.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public struct Contract:ContractProtocol {
continue
}
}
if toReturn == nil {
let defaultConstructor = ABIElement.constructor(ABIElement.Constructor.init(inputs: [], constant: false, payable: false))
return defaultConstructor
}
return toReturn
}

Expand Down Expand Up @@ -99,15 +103,8 @@ public struct Contract:ContractProtocol {
}

public func deploy(bytecode:Data, parameters: [AnyObject] = [AnyObject](), extraData: Data = Data(), options: Web3Options?) -> EthereumTransaction? {
var to:EthereumAddress
let to:EthereumAddress = EthereumAddress.contractDeploymentAddress()
let mergedOptions = Web3Options.merge(self.options, with: options)
if (self.address != nil) {
to = self.address!
} else if let toFound = mergedOptions?.to, toFound.isValid {
to = toFound
} else {
return nil
}

var gasLimit:BigUInt
if let gasInOptions = mergedOptions?.gasLimit {
Expand Down
14 changes: 5 additions & 9 deletions web3swift/Contract/Classes/ContractABIv2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public struct ContractV2:ContractProtocol {
continue
}
}
if toReturn == nil {
let defaultConstructor = ABIv2.Element.constructor(ABIv2.Element.Constructor.init(inputs: [], constant: false, payable: false))
return defaultConstructor
}
return toReturn
}

Expand Down Expand Up @@ -104,16 +108,8 @@ public struct ContractV2:ContractProtocol {
}

public func deploy(bytecode:Data, parameters: [AnyObject] = [AnyObject](), extraData: Data = Data(), options: Web3Options?) -> EthereumTransaction? {
var to:EthereumAddress
let to:EthereumAddress = EthereumAddress.contractDeploymentAddress()
let mergedOptions = Web3Options.merge(self.options, with: options)
if (self.address != nil) {
to = self.address!
} else if let toFound = mergedOptions?.to, toFound.isValid {
to = toFound
} else {
return nil
}

var gasLimit:BigUInt
if let gasInOptions = mergedOptions?.gasLimit {
gasLimit = gasInOptions
Expand Down
48 changes: 35 additions & 13 deletions web3swift/KeystoreManager/Classes/EthereumAddress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,46 @@ import Foundation
import BigInt

public struct EthereumAddress: Equatable {
public enum AddressType {
case normal
case contractDeployment
}

public var isValid: Bool {
get {
return (self.addressData.count == 20);
switch self.type {
case .normal:
return (self.addressData.count == 20)
case .contractDeployment:
return true
}

}
}
var _address: String

public var type: AddressType = .normal
public static func ==(lhs: EthereumAddress, rhs: EthereumAddress) -> Bool {
return lhs.address.lowercased() == rhs.address.lowercased()
return lhs.address.lowercased() == rhs.address.lowercased() && lhs.type == rhs.type
}

public var addressData: Data {
get {
let dataArray = Array<UInt8>(hex: _address.lowercased().stripHexPrefix())
guard let d = Data(dataArray).setLengthLeft(20)
else {
return Data()
switch self.type {
case .normal:
guard let dataArray = Data.fromHex(_address) else {return Data()}
guard let d = dataArray.setLengthLeft(20) else { return Data()}
return d
case .contractDeployment:
return Data()
}
return d
}
}
public var address:String {
get {
switch self.type {
case .normal:
return EthereumAddress.toChecksumAddress(_address)!
case .contractDeployment:
return "0x"
}
}

Expand All @@ -56,11 +72,17 @@ public struct EthereumAddress: Equatable {
return ret
}

public init(_ addressString:String) {
_address = addressString
public init(_ addressString:String, type: AddressType = .normal) {
self._address = addressString
self.type = type
}

public init(_ addressData:Data, type: AddressType = .normal) {
self._address = addressData.toHexString().addHexPrefix()
self.type = type
}

public init(_ addressData:Data) {
_address = addressData.toHexString().addHexPrefix()
public static func contractDeploymentAddress() -> EthereumAddress {
return EthereumAddress("0x", type: .contractDeployment)
}
}
Loading