Skip to content

Commit ad3d00d

Browse files
authored
Merge branch 'develop' into remove-Promises
2 parents ec3d2d3 + f2f613a commit ad3d00d

33 files changed

+3430
-879
lines changed

Sources/web3swift/Contract/EthereumContract.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,18 @@ public struct EthereumContract: ContractProtocol {
114114
} else if extraData != Data() {
115115
fullData.append(extraData)
116116
}
117-
let transaction = EthereumTransaction(gasPrice: BigUInt(0), gasLimit: BigUInt(0), to: to, value: BigUInt(0), data: fullData)
117+
let params = EthereumParameters(gasLimit: BigUInt(0), gasPrice: BigUInt(0))
118+
let transaction = EthereumTransaction(to: to, value: BigUInt(0), data: fullData, parameters: params)
118119
return transaction
119120
}
120121

121122
public func method(_ method: String = "fallback", parameters: [AnyObject] = [AnyObject](), extraData: Data = Data()) -> EthereumTransaction? {
122123
guard let to = self.address else {return nil}
123124

124125
if (method == "fallback") {
125-
let transaction = EthereumTransaction(gasPrice: BigUInt(0), gasLimit: BigUInt(0), to: to, value: BigUInt(0), data: extraData)
126+
let params = EthereumParameters(gasLimit: BigUInt(0), gasPrice: BigUInt(0))
127+
let transaction = EthereumTransaction(to: to, value: BigUInt(0), data: extraData, parameters: params)
128+
126129
return transaction
127130
}
128131
let foundMethod = self.methods.filter { (key, value) -> Bool in
@@ -131,7 +134,8 @@ public struct EthereumContract: ContractProtocol {
131134
guard foundMethod.count == 1 else {return nil}
132135
let abiMethod = foundMethod[method]
133136
guard let encodedData = abiMethod?.encodeParameters(parameters) else {return nil}
134-
let transaction = EthereumTransaction(gasPrice: BigUInt(0), gasLimit: BigUInt(0), to: to, value: BigUInt(0), data: encodedData)
137+
let params = EthereumParameters(gasLimit: BigUInt(0), gasPrice: BigUInt(0))
138+
let transaction = EthereumTransaction(to: to, value: BigUInt(0), data: encodedData, parameters: params)
135139
return transaction
136140
}
137141

Sources/web3swift/Convenience/Array+Extension.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//
66

77
import Foundation
8+
import BigInt
89

910
extension Array {
1011
public func split(intoChunksOf chunkSize: Int) -> [[Element]] {
@@ -14,3 +15,41 @@ extension Array {
1415
}
1516
}
1617
}
18+
19+
extension Array where Element: Comparable {
20+
/// Sorts array and drops most and least values.
21+
/// - Returns: Sorted array without most and least values, nil if `array.count` <= 2
22+
func cropAnomalyValues() -> Self? {
23+
var sortedArray = self.sorted()
24+
// Array should at least counts two to pass that formations.
25+
guard sortedArray.count > 1 else { return nil }
26+
sortedArray.removeLast()
27+
sortedArray.removeFirst()
28+
return sortedArray
29+
}
30+
}
31+
32+
extension Array where Element: BinaryInteger {
33+
// TODO: Make me generic
34+
/// Calculates mean value of a dataset
35+
/// - Returns: Mean value of a dataset, nil if dataset is empty
36+
func mean() -> BigUInt? {
37+
guard !self.isEmpty else { return nil }
38+
return BigUInt(self.reduce(0, +)) / BigUInt(self.count)
39+
}
40+
41+
42+
/// Calculates percentile of dataset on which get called.
43+
/// - Parameter value: Percentile value.
44+
/// - Returns: Item from dataset that is belongs to given percentile, nil if dataset is empty.
45+
func percentile(of value: Double) -> Element? {
46+
guard !self.isEmpty else { return nil }
47+
48+
let normalizedValue = value / 100 * Double(self.count)
49+
let index = Int(ceil(normalizedValue))
50+
51+
let sorted_data = self.sorted()
52+
guard index < self.count else { return sorted_data[sorted_data.count - 1] }
53+
return sorted_data[index]
54+
}
55+
}

Sources/web3swift/Convenience/Decodable+Extensions.swift

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extension KeyedDecodingContainer {
3535
/// for the given key.
3636
/// - throws: `DecodingError.valueNotFound` if `self` has a null entry for
3737
/// the given key.
38+
@available(*, deprecated, message: "Use decodeHex insetad")
3839
public func decode(_ type: [Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [Any] {
3940
var values = try nestedUnkeyedContainer(forKey: key)
4041
return try values.decode(type)
@@ -52,6 +53,7 @@ extension KeyedDecodingContainer {
5253
/// for the given key.
5354
/// - throws: `DecodingError.valueNotFound` if `self` has a null entry for
5455
/// the given key.
56+
@available(*, deprecated, message: "Use decodeHex() insetad")
5557
public func decode(_ type: [String: Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [String: Any] {
5658
let values = try nestedContainer(keyedBy: AnyCodingKey.self, forKey: key)
5759
return try values.decode(type)
@@ -70,6 +72,7 @@ extension KeyedDecodingContainer {
7072
/// the value is a null value.
7173
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
7274
/// is not convertible to the requested type.
75+
@available(*, deprecated, message: "In next version Will be replaced by decodeHexIfPresent() insetad")
7376
public func decodeIfPresent(_ type: [Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [Any]? {
7477
guard contains(key),
7578
try decodeNil(forKey: key) == false else { return nil }
@@ -89,26 +92,107 @@ extension KeyedDecodingContainer {
8992
/// the value is a null value.
9093
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value
9194
/// is not convertible to the requested type.
95+
@available(*, deprecated, message: "In next version Will be replaced by decodeHexIfPresent() insetad")
9296
public func decodeIfPresent(_ type: [String: Any].Type, forKey key: KeyedDecodingContainer<K>.Key) throws -> [String: Any]? {
9397
guard contains(key),
9498
try decodeNil(forKey: key) == false else { return nil }
9599
return try decode(type, forKey: key)
96100
}
97101

98-
/// Decodes a value of the given key from Hex to BigUInt
102+
/// Decodes a value of the given key from Hex to `DecodableFromHex`
99103
///
100-
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`
104+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `UInt.Type`
101105
///
102106
/// - Parameter type: Generic type `T` wich conforms to `DecodableFromHex` protocol
103107
/// - 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(fromHex: string) else { throw Web3Error.dataError }
108+
/// - Returns: A decoded value of type `T`
109+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `DecodableFromHex`.
110+
public func decodeHex<T: DecodableFromHex>(_ type: T.Type, forKey: KeyedDecodingContainer<K>.Key) throws -> T {
111+
let hexString = try self.decode(String.self, forKey: forKey)
112+
guard let number = T(fromHex: hexString) else { throw Web3Error.dataError }
110113
return number
111114
}
115+
116+
/// Decodes a value of the given key from Hex to `[DecodableFromHex]`
117+
///
118+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `UInt.Type`
119+
///
120+
/// - Parameter type: Array of a generic type `T` wich conforms to `DecodableFromHex` protocol
121+
/// - Parameter key: The key that the decoded value is associated with.
122+
/// - Returns: A decoded value of type `T`
123+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `[[DecodableFromHex]]`.
124+
public func decodeHex<T: DecodableFromHex>(_ type: [T].Type, forKey: KeyedDecodingContainer<K>.Key) throws -> [T] {
125+
var container = try nestedUnkeyedContainer(forKey: forKey)
126+
guard let array = try? container.decodeHex(type) else { throw Web3Error.dataError }
127+
return array
128+
}
129+
130+
/// Decodes a value of the given key from Hex to `[DecodableFromHex]`
131+
///
132+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `EthereumAddress`, `UInt.Type`
133+
///
134+
/// - Parameter type: Array of a generic type `T` wich conforms to `DecodableFromHex` protocol
135+
/// - Parameter key: The key that the decoded value is associated with.
136+
/// - Returns: A decoded value of type `T`
137+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `[[DecodableFromHex]]`.
138+
public func decodeHex<T: DecodableFromHex>(_ type: [[T]].Type, forKey: KeyedDecodingContainer<K>.Key) throws -> [[T]] {
139+
var container = try nestedUnkeyedContainer(forKey: forKey)
140+
guard let array = try? container.decodeHex(type) else { throw Web3Error.dataError }
141+
return array
142+
}
143+
144+
/// Decodes a value of the given key from Hex to `DecodableFromHex`
145+
///
146+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `UInt.Type`
147+
///
148+
/// - Parameter type: Generic type `T` wich conforms to `DecodableFromHex` protocol
149+
/// - Parameter key: The key that the decoded value is associated with.
150+
/// - Returns: A decoded value of type `T`, or nil if key is not present
151+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `DecodableFromHex`.
152+
public func decodeHexIfPresent<T: DecodableFromHex>(_ type: T.Type, forKey: KeyedDecodingContainer<K>.Key) throws -> T? {
153+
guard contains(forKey) else { return nil }
154+
return try decodeHex(type, forKey: forKey)
155+
}
156+
157+
}
158+
159+
public extension UnkeyedDecodingContainer {
160+
/// Decodes a unkeyed value from hex to `[DecodableFromHex]`
161+
///
162+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `EthereumAddress`
163+
///
164+
/// - Parameter type: Generic type `T` wich conforms to `DecodableFromHex` protocol
165+
/// - Parameter key: The key that the decoded value is associated with.
166+
/// - Returns: A decoded value of type `BigUInt`
167+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `[DecodableFromHex]`.
168+
mutating func decodeHex<T: DecodableFromHex>(_ type: [T].Type) throws -> [T] {
169+
var array: [T] = []
170+
while !isAtEnd {
171+
let hexString = try decode(String.self)
172+
guard let item = T(fromHex: hexString) else { continue }
173+
array.append(item)
174+
}
175+
return array
176+
}
177+
178+
179+
/// Decodes a unkeyed value from Hex to `DecodableFromHex`
180+
///
181+
/// Currently this method supports only `Data.Type`, `BigUInt.Type`, `Date.Type`, `EthereumAddress`
182+
///
183+
/// - Parameter type: Generic type `T` wich conforms to `DecodableFromHex` protocol
184+
/// - Parameter key: The key that the decoded value is associated with.
185+
/// - Returns: A decoded value of type `BigUInt`
186+
/// - throws: `Web3Error.dataError` if value associated with key are unable to be initialized as `[[DecodableFromHex]]`.
187+
mutating func decodeHex<T: DecodableFromHex>(_ type: [[T]].Type) throws -> [[T]] {
188+
var array: [[T]] = []
189+
while !isAtEnd {
190+
var container = try nestedUnkeyedContainer()
191+
let intArr = try container.decodeHex([T].self)
192+
array.append(intArr)
193+
}
194+
return array
195+
}
112196
}
113197

114198
public protocol DecodableFromHex: Decodable {
@@ -123,6 +207,12 @@ extension Data: DecodableFromHex {
123207
}
124208
}
125209

210+
extension UInt: DecodableFromHex {
211+
public init?(fromHex hexString: String) {
212+
self.init(hexString.stripHexPrefix(), radix: 16)
213+
}
214+
}
215+
126216
extension BigUInt: DecodableFromHex {
127217
public init?(fromHex hexString: String) {
128218
self.init(hexString.stripHexPrefix(), radix: 16)
@@ -144,6 +234,7 @@ extension EthereumAddress: DecodableFromHex {
144234
}
145235
}
146236

237+
// deprecated, should be removed in 3.0.0
147238
private extension KeyedDecodingContainer {
148239
func decode(_ type: [String: Any].Type) throws -> [String: Any] {
149240
var dictionary: [String: Any] = [:]
@@ -168,6 +259,7 @@ private extension KeyedDecodingContainer {
168259
}
169260
}
170261

262+
// deprecated, should be removed in 3.0.0
171263
private extension UnkeyedDecodingContainer {
172264
mutating func decode(_ type: [Any].Type) throws -> [Any] {
173265
var elements: [Any] = []

Sources/web3swift/HookedFunctions/Web3+BrowserFunctions.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,11 @@ extension web3.BrowserFunctions {
134134
var options = opts
135135
guard let _ = options.from else {return (nil, nil)}
136136
let gasPrice = try await self.web3.eth.getGasPrice()
137-
transaction.gasPrice = gasPrice
137+
transaction.parameters.gasPrice = gasPrice
138138
options.gasPrice = .manual(gasPrice)
139139
guard let gasEstimate = await self.estimateGas(transaction, transactionOptions: options) else {return (nil, nil)}
140-
transaction.gasLimit = gasEstimate
140+
transaction.parameters.gasLimit = gasEstimate
141+
141142
options.gasLimit = .limited(gasEstimate)
142143
print(transaction)
143144
return (transaction, options)
@@ -176,18 +177,18 @@ extension web3.BrowserFunctions {
176177
guard let noncePolicy = transactionOptions.nonce else {return nil}
177178
switch gasPricePolicy {
178179
case .manual(let gasPrice):
179-
transaction.gasPrice = gasPrice
180+
transaction.parameters.gasPrice = gasPrice
180181
default:
181182
let gasPrice = try await self.web3.eth.getGasPrice()
182-
transaction.gasPrice = gasPrice
183+
transaction.parameters.gasPrice = gasPrice
183184
}
184185

185186
switch gasLimitPolicy {
186187
case .manual(let gasLimit):
187-
transaction.gasLimit = gasLimit
188+
transaction.parameters.gasLimit = gasLimit
188189
default:
189190
let gasLimit = try await self.web3.eth.estimateGas(transaction, transactionOptions: transactionOptions)
190-
transaction.gasLimit = gasLimit
191+
transaction.parameters.gasLimit = gasLimit
191192
}
192193

193194
switch noncePolicy {
@@ -205,7 +206,7 @@ extension web3.BrowserFunctions {
205206
guard let keystore = keystoreManager.walletForAddress(from) else {return nil}
206207
try Web3Signer.signTX(transaction: &transaction, keystore: keystore, account: from, password: password)
207208
print(transaction)
208-
let signedData = transaction.encode(forSignature: false, chainID: nil)?.toHexString().addHexPrefix()
209+
let signedData = transaction.encode()?.toHexString().addHexPrefix()
209210
return signedData
210211
} catch {
211212
return nil
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Promise+Web3+Eth+FeeHistory.swift
3+
// web3swift
4+
//
5+
// Created by Yaroslav on 11.04.2022.
6+
// Copyright © 2022 web3swift. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import PromiseKit
11+
import BigInt
12+
13+
extension web3.Eth {
14+
func feeHistory(blockCount: BigUInt, block: String, percentiles:[Double]) throws -> Web3.Oracle.FeeHistory {
15+
let request = JSONRPCRequestFabric.prepareRequest(.feeHistory, parameters: [blockCount.description.addHexPrefix(), block, percentiles])
16+
let rp = web3.dispatch(request)
17+
let queue = web3.requestDispatcher.queue
18+
return try rp.map(on: queue) { response in
19+
guard let value: Web3.Oracle.FeeHistory = response.getValue() else {
20+
if response.error != nil {
21+
throw Web3Error.nodeError(desc: response.error!.message)
22+
}
23+
throw Web3Error.nodeError(desc: "Invalid value from Ethereum node")
24+
}
25+
return value
26+
}.wait()
27+
}
28+
}

Sources/web3swift/Promises/Promise+Web3+Eth+SendRawTransaction.swift

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,36 @@ import Foundation
88

99

1010
extension web3.Eth {
11-
public func sendRawTransactionPromise(_ transaction: Data) async throws -> TransactionSendingResult {
12-
guard let deserializedTX = EthereumTransaction.fromRaw(transaction) else {
13-
throw Web3Error.processingError(desc: "Serialized TX is invalid")
11+
public func sendRawTransactionPromise(_ transaction: Data) -> Promise<TransactionSendingResult> {
12+
guard let deserializedTX = EthereumTransaction(rawValue: transaction) else {
13+
let promise = Promise<TransactionSendingResult>.pending()
14+
promise.resolver.reject(Web3Error.processingError(desc: "Serialized TX is invalid"))
15+
return promise.promise
1416
}
1517
return try await sendRawTransactionPromise(deserializedTX)
1618
}
1719

18-
public func sendRawTransactionPromise(_ transaction: EthereumTransaction) async throws -> TransactionSendingResult {
19-
20-
guard let request = EthereumTransaction.createRawTransaction(transaction: transaction) else {
21-
throw Web3Error.processingError(desc: "Transaction is invalid")
22-
}
23-
let response = try await web3.dispatch(request)
24-
25-
guard let value: String = response.getValue() else {
26-
if response.error != nil {
27-
throw Web3Error.nodeError(desc: response.error!.message)
20+
public func sendRawTransactionPromise(_ transaction: EthereumTransaction) -> Promise<TransactionSendingResult>{
21+
let queue = web3.requestDispatcher.queue
22+
do {
23+
guard let request = EthereumTransaction.createRawTransaction(transaction: transaction) else {
24+
throw Web3Error.processingError(desc: "Transaction is invalid")
25+
}
26+
let rp = web3.dispatch(request)
27+
return rp.map(on: queue) { response in
28+
guard let value: String = response.getValue() else {
29+
if response.error != nil {
30+
throw Web3Error.nodeError(desc: response.error!.message)
31+
}
32+
throw Web3Error.nodeError(desc: "Invalid value from Ethereum node")
33+
}
34+
let result = TransactionSendingResult(transaction: transaction, hash: value)
35+
for hook in self.web3.postSubmissionHooks {
36+
hook.queue.async {
37+
hook.function(result)
38+
}
39+
}
40+
return result
2841
}
2942
throw Web3Error.nodeError(desc: "Invalid value from Ethereum node")
3043
}

Sources/web3swift/SwiftRLP/RLP.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public struct RLP {
113113
return encoded.bytes[0]
114114
}
115115

116+
// FIXME: Make encode generic to avoid casting it's argument to [AnyObject]
116117
public static func encode(_ elements: Array<AnyObject>) -> Data? {
117118
var encodedData = Data()
118119
for e in elements {

0 commit comments

Comments
 (0)