9
9
import Foundation
10
10
import BigInt
11
11
12
- extension web3 . Eth {
12
+ extension Web3 {
13
13
/// Oracle is the class to do a transaction fee suggestion
14
14
final public class Oracle {
15
15
@@ -33,10 +33,10 @@ extension web3.Eth {
33
33
/// Oracle initializer
34
34
/// - Parameters:
35
35
/// - provider: Web3 Ethereum provider
36
- /// - block: Number of block from which counts starts
36
+ /// - block: Number of block from which counts starts backward
37
37
/// - blockCount: Count of block to calculate statistics
38
38
/// - percentiles: Percentiles of fees which will split in fees history
39
- public init ( _ provider: web3 , block: String = " latest " , blockCount: BigUInt = 20 , percentiles: [ Double ] = [ 10 , 50 , 90 ] ) {
39
+ public init ( _ provider: web3 , block: String = " latest " , blockCount: BigUInt = 20 , percentiles: [ Double ] = [ 25 , 50 , 75 ] ) {
40
40
self . web3Provider = provider
41
41
self . block = block
42
42
self . blockCount = blockCount
@@ -72,7 +72,7 @@ extension web3.Eth {
72
72
private func soft( twoDimentsion array: [ [ BigUInt ] ] ) -> [ BigUInt ] {
73
73
/// We've got `[[min],[middle],[max]]` 2 dimensional array
74
74
/// we're getting `[min, middle, max].count == self.percentiles.count`,
75
- /// where each value are mean from the input percentile array
75
+ /// where each value are mean from the input percentile arrays
76
76
array. compactMap { percentileArray -> [ BigUInt ] ? in
77
77
guard !percentileArray. isEmpty else { return nil }
78
78
// swiftlint:disable force_unwrapping
@@ -98,28 +98,37 @@ extension web3.Eth {
98
98
}
99
99
100
100
/// Suggesting tip values
101
- /// - Returns: `[percentile 1, percentile 2, percentile 3 ].count == self.percentile.count`
101
+ /// - Returns: `[percentile_1, percentile_2, percentile_3, ... ].count == self.percentile.count`
102
102
/// by default there's 3 percentile.
103
103
private func suggestTipValue( ) throws -> [ BigUInt ] {
104
+ var rearrengedArray : [ [ BigUInt ] ] = [ ]
105
+
104
106
/// reaarange `[[min, middle, max]]` to `[[min], [middle], [max]]`
105
- let rearrengedArray = try suggestGasValues ( ) . reward
106
- . map { internalArray -> [ BigUInt ] in
107
- var newArray = [ BigUInt] ( )
108
- internalArray. enumerated ( ) . forEach { newArray [ $0] = $1 }
109
- return newArray
107
+ try suggestGasValues ( ) . reward
108
+ . forEach { percentiles in
109
+ percentiles. enumerated ( ) . forEach { ( index, percentile) in
110
+ /// if `rearrengedArray` have not that enough items
111
+ /// as `percentiles` current item index
112
+ if rearrengedArray. endIndex <= index {
113
+ /// append its as an array
114
+ rearrengedArray. append ( [ percentile] )
115
+ } else {
116
+ /// append `percentile` value to appropriate `percentiles` array.
117
+ rearrengedArray [ index] . append ( percentile)
118
+ }
119
+ }
110
120
}
111
121
return soft ( twoDimentsion: rearrengedArray)
112
122
}
113
123
114
124
private func suggestBaseFee( ) throws -> [ BigUInt ] {
115
- calculatePercentiles ( for: try suggestGasValues ( ) . baseFeePerGas)
125
+ self . feeHistory = try suggestGasValues ( )
126
+ return calculatePercentiles ( for: feeHistory!. baseFeePerGas)
116
127
}
117
128
118
129
private func suggestGasFeeLegacy( _ statistic: Statistic ) throws -> BigUInt {
119
130
let latestBlockNumber = try eth. getBlockNumber ( )
120
131
121
- // Assigning last block to object var to predict baseFee of the next block
122
- // latestBlock = try eth.getBlockByNumber(latestBlockNumber)
123
132
// TODO: Make me work with cache
124
133
let lastNthBlockGasPrice = try ( latestBlockNumber - blockCount ... latestBlockNumber)
125
134
. map { try eth. getBlockByNumber ( $0, fullTransactions: true ) }
@@ -136,17 +145,14 @@ extension web3.Eth {
136
145
}
137
146
}
138
147
139
- public extension web3 . Eth . Oracle {
148
+ public extension Web3 . Oracle {
140
149
// MARK: - Base Fee
141
- /// Base fee amount based on last Nth blocks
150
+ /// Softed baseFee amount
142
151
///
143
152
/// Normalized means that most high and most low value were droped from calculation.
144
153
///
145
- /// Nth block may include empty ones.
146
- ///
147
- /// - Parameter statistic: Statistic to apply for base fee calculation
148
154
/// - Returns: Suggested base fee amount according to statistic, nil if failed to perdict
149
- func predictBaseFee ( ) -> [ BigUInt ] {
155
+ var baseFeePercentiles : [ BigUInt ] {
150
156
guard let value = try ? suggestBaseFee ( ) else { return [ ] }
151
157
return value
152
158
}
@@ -160,7 +166,7 @@ public extension web3.Eth.Oracle {
160
166
///
161
167
/// - Parameter statistic: Statistic to apply for tip calculation
162
168
/// - Returns: Suggested tip amount according to statistic, nil if failed to perdict
163
- func predictTip ( ) -> [ BigUInt ] {
169
+ var tipFeePercentiles : [ BigUInt ] {
164
170
guard let value = try ? suggestTipValue ( ) else { return [ ] }
165
171
return value
166
172
}
@@ -171,7 +177,7 @@ public extension web3.Eth.Oracle {
171
177
/// - baseFee: Statistic to apply for baseFee
172
178
/// - tip: Statistic to apply for tip
173
179
/// - Returns: Tuple where `baseFee` — base fee, `tip` — tip, nil if failed to predict
174
- func predictBothFees ( ) -> ( baseFee: [ BigUInt ] , tip: [ BigUInt ] ) ? {
180
+ var bothFeesPercentiles : ( baseFee: [ BigUInt ] , tip: [ BigUInt ] ) ? {
175
181
guard let baseFee = try ? suggestBaseFee ( ) else { return nil }
176
182
guard let tip = try ? suggestTipValue ( ) else { return nil }
177
183
@@ -188,7 +194,7 @@ public extension web3.Eth.Oracle {
188
194
// }
189
195
}
190
196
191
- public extension web3 . Eth . Oracle {
197
+ public extension Web3 . Oracle {
192
198
// TODO: Make me struct and encapsulate math within to make me extendable
193
199
enum Statistic {
194
200
/// Mininum statistic
@@ -202,7 +208,7 @@ public extension web3.Eth.Oracle {
202
208
}
203
209
}
204
210
205
- public extension web3 . Eth . Oracle {
211
+ extension Web3 . Oracle {
206
212
struct FeeHistory {
207
213
let timestamp = Date ( )
208
214
let baseFeePerGas : [ BigUInt ]
@@ -212,7 +218,7 @@ public extension web3.Eth.Oracle {
212
218
}
213
219
}
214
220
215
- extension web3 . Eth . Oracle . FeeHistory : Decodable {
221
+ extension Web3 . Oracle . FeeHistory : Decodable {
216
222
enum CodingKeys : String , CodingKey {
217
223
case baseFeePerGas
218
224
case gasUsedRatio
@@ -229,35 +235,3 @@ extension web3.Eth.Oracle.FeeHistory: Decodable {
229
235
self . reward = try values. decodeHex ( [ [ BigUInt ] ] . self, forKey: . reward)
230
236
}
231
237
}
232
-
233
- extension Array where Element: Comparable {
234
-
235
- /// Sorts array and drops most and least values.
236
- /// - Returns: Sorted array without most and least values, nil if `array.count` <= 2
237
- func cropAnomalyValues( ) -> Self ? {
238
- var sortedArray = self . sorted ( )
239
- // Array should at least counts two to pass that formations.
240
- guard sortedArray. count > 1 else { return nil }
241
- sortedArray. removeLast ( )
242
- sortedArray. removeFirst ( )
243
- return sortedArray
244
- }
245
- }
246
-
247
- extension Array where Element: BinaryInteger {
248
- func mean( ) -> BigUInt ? {
249
- guard !self . isEmpty else { return nil }
250
- return BigUInt ( self . reduce ( 0 , + ) ) / BigUInt( self . count)
251
- }
252
-
253
- func percentile( of value: Double ) -> BigUInt ? {
254
- guard !self . isEmpty else { return nil }
255
-
256
- let sorted_data = self . sorted ( )
257
- // if self.count % 2 == 1 {
258
- return BigUInt ( sorted_data [ Int ( floor ( Double ( self . count) / value / 10 ) ) ] )
259
- // } else {
260
- // return BigUInt(sorted_data[self.count / Int(value) / 10] + sorted_data[(self.count / Int(value) / 10) - 1] /( value) / 10)
261
- // }
262
- }
263
- }
0 commit comments