Skip to content

Commit 89f362f

Browse files
chore: merged with develop
2 parents 55322f6 + e30d812 commit 89f362f

22 files changed

+1110
-519
lines changed

.swiftlint.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
excluded:
2+
- Carthage
3+
- Pods
4+
- .build
5+
- Build
6+
- DerivedData
7+
8+
disabled_rules:
9+
- type_name
10+
- identifier_name
11+
- line_length
12+
- multiple_closures_with_trailing_closure
13+
- todo
14+
15+
opt_in_rules:
16+
- weak_delegate
17+
- unused_import
18+
- unneeded_parentheses_in_closure_argument
19+
- trailing_closure
20+
- static_operator
21+
- redundant_nil_coalescing
22+
- override_in_extension
23+
- legacy_objc_type
24+
- implicitly_unwrapped_optional
25+
- force_unwrapping
26+
- empty_string
27+
- closure_body_length
28+
- fallthrough
29+
- indentation_width
30+
31+
# force warnings
32+
force_cast: error
33+
force_try: error
34+
35+
custom_rules:
36+
commented_out_code:
37+
included: ".*\\.swift" # regex that defines paths to include during linting. optional.
38+
excluded: ".*Test(s)?\\.swift" # regex that defines paths to exclude during linting. optional
39+
name: "Commented out code" # rule name. optional.
40+
regex: "^\\/\\/\\s*(@|\\.?([a-z]|(\\})))" # matching pattern
41+
capture_group: 0 # number of regex capture group to highlight the rule violation at. optional.
42+
match_kinds: # SyntaxKinds to match. optional.
43+
- comment
44+
message: "No commented code in devel branch allowed." # violation message. optional.
45+
severity: warning # violation severity. optional.

Sources/web3swift/Contract/EthereumContract.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public struct EthereumContract: ContractProtocol {
3333
var toReturn = [String: ABI.Element]()
3434
for m in self._abi {
3535
switch m {
36-
case .function(let function):
36+
case .function(let function):
3737
guard let name = function.name else {continue}
3838
toReturn[name] = m
3939
default:
@@ -50,7 +50,7 @@ public struct EthereumContract: ContractProtocol {
5050
break
5151
}
5252
switch m {
53-
case .constructor(_):
53+
case .constructor(_):
5454
toReturn = m
5555
break
5656
default:
@@ -68,10 +68,10 @@ public struct EthereumContract: ContractProtocol {
6868
var toReturn = [String: ABI.Element.Event]()
6969
for m in self._abi {
7070
switch m {
71-
case .event(let event):
71+
case .event(let event):
7272
let name = event.name
7373
toReturn[name] = event
74-
default:
74+
default:
7575
continue
7676
}
7777
}

Sources/web3swift/Convenience/Base58.swift

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ struct Base58 {
5656
}
5757

5858
for b in base58 {
59-
// str = "\(str)\(base58Alphabet[String.Index(encodedOffset: Int(b))])"
6059
str = "\(str)\(base58Alphabet[String.Index(utf16Offset: Int(b), in: base58Alphabet)])"
6160
}
6261

@@ -67,23 +66,27 @@ struct Base58 {
6766
static func bytesFromBase58(_ base58: String) -> [UInt8] {
6867
// remove leading and trailing whitespaces
6968
let string = base58.trimmingCharacters(in: CharacterSet.whitespaces)
70-
7169
guard !string.isEmpty else { return [] }
7270

73-
var zerosCount = 0
74-
var length = 0
71+
// count leading ASCII "1"'s [decodes directly to binary zero bytes]
72+
var leadingZeros = 0
7573
for c in string {
7674
if c != "1" { break }
77-
zerosCount += 1
75+
leadingZeros += 1
7876
}
7977

80-
let size = string.lengthOfBytes(using: String.Encoding.utf8) * 733 / 1000 + 1 - zerosCount
81-
var base58: [UInt8] = Array(repeating: 0, count: size)
78+
// calculate the size of the decoded output, rounded up
79+
let size = (string.lengthOfBytes(using: String.Encoding.utf8) - leadingZeros) * 733 / 1000 + 1
80+
81+
// allocate a buffer large enough for the decoded output
82+
var base58: [UInt8] = Array(repeating: 0, count: size + leadingZeros)
83+
84+
// decode what remains of the data
85+
var length = 0
8286
for c in string where c != " " {
8387
// search for base58 character
84-
guard let base58Index = base58Alphabet.index(of: c) else { return [] }
88+
guard let base58Index = base58Alphabet.firstIndex(of: c) else { return [] }
8589

86-
// var carry = base58Index.encodedOffset
8790
var carry = base58Index.utf16Offset(in: base58Alphabet)
8891
var i = 0
8992
for j in 0...base58.count where carry != 0 || i < length {
@@ -97,20 +100,16 @@ struct Base58 {
97100
length = i
98101
}
99102

100-
// skip leading zeros
101-
var zerosToRemove = 0
102-
103+
// calculate how many leading zero bytes we have
104+
var totalZeros = 0
103105
for b in base58 {
104106
if b != 0 { break }
105-
zerosToRemove += 1
107+
totalZeros += 1
106108
}
107-
base58.removeFirst(zerosToRemove)
109+
// remove the excess zero bytes
110+
base58.removeFirst(totalZeros - leadingZeros)
108111

109-
var result: [UInt8] = Array(repeating: 0, count: zerosCount)
110-
for b in base58 {
111-
result.append(b)
112-
}
113-
return result
112+
return base58
114113
}
115114
}
116115

@@ -158,11 +157,4 @@ extension String {
158157
return bytes
159158
}
160159

161-
// public var littleEndianHexToUInt: UInt {
162-
// let data = Data.fromHex(self)!
163-
// let revensed =
164-
// return UInt(sel)
165-
// return UInt(self.dataWithHexString().bytes.reversed().fullHexString, radix: 16)!
166-
// }
167-
168160
}

Sources/web3swift/Convenience/Decodable+Extensions.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by levantAJ on 1/18/19.
66
// Copyright © 2019 levantAJ. All rights reserved.
77
//
8+
import BigInt
89
import Foundation
910

1011
struct AnyCodingKey: CodingKey {
@@ -93,6 +94,50 @@ extension KeyedDecodingContainer {
9394
try decodeNil(forKey: key) == false else { return nil }
9495
return try decode(type, forKey: key)
9596
}
97+
98+
/// Decodes a value of the given key from Hex to BigUInt
99+
///
100+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`
101+
///
102+
/// - Parameter type: Generic type `T` wich conforms to `DecodableFromHex` protocol
103+
/// - Parameter key: The key that the decoded value is associated with.
104+
/// - Returns: A decoded value of type `BigUInt`
105+
/// - throws: `Web3Error.dataError` if value associated with key are unable
106+
/// to be initialized as `BigUInt`.
107+
public func decodeHex<T: DecodableFromHex>(to type: T.Type, key: KeyedDecodingContainer<K>.Key) throws -> T {
108+
let string = try self.decode(String.self, forKey: key)
109+
guard let number = T(from: string) else { throw Web3Error.dataError }
110+
return number
111+
}
112+
}
113+
114+
public protocol DecodableFromHex: Decodable {
115+
init?(from hexString: String)
116+
}
117+
118+
extension Data: DecodableFromHex {
119+
public init?(from hexString: String) {
120+
self.init()
121+
guard let tmp = Self.fromHex(hexString) else { return nil }
122+
self = tmp
123+
}
124+
}
125+
126+
extension BigUInt: DecodableFromHex {
127+
public init?(from hexString: String) {
128+
self.init()
129+
guard let tmp = BigUInt(hexString.stripHexPrefix(), radix: 16) else { return nil }
130+
self = tmp
131+
}
132+
}
133+
134+
extension Date: DecodableFromHex {
135+
public init?(from hexString: String) {
136+
self.init()
137+
let stripedHexString = hexString.stripHexPrefix()
138+
guard let timestampInt = UInt64(stripedHexString, radix: 16) else { return nil }
139+
self = Date(timeIntervalSince1970: TimeInterval(timestampInt))
140+
}
96141
}
97142

98143
private extension KeyedDecodingContainer {

Sources/web3swift/EthereumABI/ABIElements.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
//
1+
//
22
// Created by Alex Vlasov on 25/10/2018.
33
// Copyright © 2018 Alex Vlasov. All rights reserved.
4-
//
4+
//
55

66
import Foundation
77
import BigInt

Sources/web3swift/EthereumABI/ABIEncoding.swift

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
//
1+
//
22
// Created by Alex Vlasov on 25/10/2018.
33
// Copyright © 2018 Alex Vlasov. All rights reserved.
4-
//
4+
//
55

66
import Foundation
77
import BigInt
@@ -383,3 +383,75 @@ extension ABIEncoder {
383383
return nil
384384
}
385385
}
386+
387+
// MARK: - SoliditySHA3 implementation based on web3js
388+
389+
public extension ABIEncoder {
390+
/**
391+
A convenience implementation of web3js [soliditySha3](https://web3js.readthedocs.io/en/v1.2.11/web3-utils.html?highlight=soliditySha3#soliditysha3)
392+
that is based on web3swift [`ABIEncoder`](https://github.com/skywinder/web3swift/blob/develop/Sources/web3swift/EthereumABI/ABIEncoding.swift ).
393+
*/
394+
static func soliditySha3(_ values: [Any]) throws -> Data {
395+
try abiEncode(values).sha3(.keccak256)
396+
}
397+
398+
static func soliditySha3(_ value: Any) throws -> Data {
399+
if let values = value as? [Any] {
400+
return try abiEncode(values).sha3(.keccak256)
401+
} else {
402+
return try abiEncode(value).sha3(.keccak256)
403+
}
404+
}
405+
406+
/// Using AnyObject any number can be represented as Bool and Bool can be represented as number.
407+
/// That will lead to invalid hash output. DO NOT USE THIS FUNCTION.
408+
/// This function will exist to intentionally throw an error that will raise awareness that the hash output can be potentially,
409+
/// and most likely will be, wrong.
410+
/// - Parameter values: to hash
411+
/// - Returns: solidity sha3 hash
412+
static func soliditySha3(_ values: [AnyObject]) throws -> Data {
413+
throw Web3Error.inputError(desc: "AnyObject creates ambiguity and does not guarantee that the output will be correct. Please, use `soliditySha3(Any) or soliditySha3([Any]) instead.`")
414+
}
415+
416+
/// See docs for ``soliditySha3(_ values: [AnyObject])``
417+
static func soliditySha3(_ value: AnyObject) throws -> Data {
418+
throw Web3Error.inputError(desc: "AnyObject creates ambiguity and does not guarantee that the output will be correct. Please, use `soliditySha3(Any) or soliditySha3([Any]) instead.`")
419+
}
420+
421+
static func abiEncode(_ values: [Any]) throws -> Data {
422+
return try values.map {
423+
try abiEncode($0)
424+
}.reduce(into: Data()) { partialResult, nextElement in
425+
partialResult.append(nextElement)
426+
}
427+
}
428+
429+
static func abiEncode(_ value: Any) throws -> Data {
430+
if let v = value as? Bool {
431+
return Data(v ? [0b1] : [0b0])
432+
} else if let v = value as? Int {
433+
return ABIEncoder.convertToData(BigInt(exactly: v)?.abiEncode(bits: 256)! as AnyObject)!
434+
} else if let v = value as? Int8 {
435+
return ABIEncoder.convertToData(BigInt(exactly: v)?.abiEncode(bits: 8) as AnyObject)!
436+
} else if let v = value as? Int16 {
437+
return ABIEncoder.convertToData(BigInt(exactly: v)?.abiEncode(bits: 16)! as AnyObject)!
438+
} else if let v = value as? Int32 {
439+
return ABIEncoder.convertToData(BigInt(exactly: v)?.abiEncode(bits: 32)! as AnyObject)!
440+
} else if let v = value as? Int64 {
441+
return ABIEncoder.convertToData(BigInt(exactly: v)?.abiEncode(bits: 64)! as AnyObject)!
442+
} else if let v = value as? UInt {
443+
return ABIEncoder.convertToData(BigUInt(exactly: v)?.abiEncode(bits: 256)! as AnyObject)!
444+
} else if let v = value as? UInt8 {
445+
return ABIEncoder.convertToData(BigUInt(exactly: v)?.abiEncode(bits: 8)! as AnyObject)!
446+
} else if let v = value as? UInt16 {
447+
return ABIEncoder.convertToData(BigUInt(exactly: v)?.abiEncode(bits: 16)! as AnyObject)!
448+
} else if let v = value as? UInt32 {
449+
return ABIEncoder.convertToData(BigUInt(exactly: v)?.abiEncode(bits: 32)! as AnyObject)!
450+
} else if let v = value as? UInt64 {
451+
return ABIEncoder.convertToData(BigUInt(exactly: v)?.abiEncode(bits: 64)! as AnyObject)!
452+
} else if let data = ABIEncoder.convertToData(value as AnyObject) {
453+
return data
454+
}
455+
throw Web3Error.inputError(desc: "SoliditySha3: `abiEncode` accepts an Int/UInt (any of 8, 16, 32, 64 bits long), HEX string, Bool, Data, BigInt or BigUInt instance. Given value is of type \(type(of: value)).")
456+
}
457+
}

Sources/web3swift/EthereumAddress/EthereumAddress.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,15 @@ public struct EthereumAddress: Equatable {
7272
return ret
7373
}
7474

75-
public init?(_ addressString: String, type: AddressType = .normal, ignoreChecksum: Bool = false) {
75+
public static func contractDeploymentAddress() -> EthereumAddress {
76+
return EthereumAddress("0x", type: .contractDeployment)!
77+
}
78+
}
79+
80+
/// In swift structs it's better to implement initializers in extension
81+
/// Since it's make available syntetized initializer then for free.
82+
extension EthereumAddress {
83+
public init?(_ addressString:String, type: AddressType = .normal, ignoreChecksum: Bool = false) {
7684
switch type {
7785
case .normal:
7886
guard let data = Data.fromHex(addressString) else {return nil}
@@ -108,16 +116,12 @@ public struct EthereumAddress: Equatable {
108116
}
109117
}
110118

111-
public init?(_ addressData: Data, type: AddressType = .normal) {
119+
public init?(_ addressData:Data, type: AddressType = .normal) {
112120
guard addressData.count == 20 else {return nil}
113121
self._address = addressData.toHexString().addHexPrefix()
114122
self.type = type
115123
}
116124

117-
public static func contractDeploymentAddress() -> EthereumAddress {
118-
return EthereumAddress("0x", type: .contractDeployment)!
119-
}
120-
121125
}
122126

123127
extension EthereumAddress: Hashable { }

0 commit comments

Comments
 (0)