@@ -11,7 +11,7 @@ use pragma_entities::{
11
11
Currency , Entry , NewEntry ,
12
12
} ;
13
13
14
- use crate :: handlers:: entries:: Interval ;
14
+ use crate :: handlers:: entries:: { AggregationMode , Interval } ;
15
15
use crate :: utils:: { convert_via_quote, normalize_to_decimals} ;
16
16
17
17
#[ derive( Deserialize ) ]
@@ -88,9 +88,10 @@ pub async fn routing(
88
88
interval : Interval ,
89
89
timestamp : u64 ,
90
90
is_routing : bool ,
91
+ agg_mode : AggregationMode ,
91
92
) -> Result < ( MedianEntry , u32 ) , InfraError > {
92
93
if pair_id_exist ( pool, pair_id. clone ( ) ) . await ? || !is_routing {
93
- return get_price_decimals ( pool, pair_id, interval, timestamp) . await ;
94
+ return get_price_decimals ( pool, pair_id, interval, timestamp, agg_mode ) . await ;
94
95
}
95
96
96
97
let [ base, quote] : [ & str ; 2 ] = pair_id
@@ -99,7 +100,7 @@ pub async fn routing(
99
100
. try_into ( )
100
101
. map_err ( |_| InfraError :: InternalServerError ) ?;
101
102
102
- match find_alternative_pair_price ( pool, base, quote, interval, timestamp) . await {
103
+ match find_alternative_pair_price ( pool, base, quote, interval, timestamp, agg_mode ) . await {
103
104
Ok ( result) => Ok ( result) ,
104
105
Err ( _) => Err ( InfraError :: NotFound ) ,
105
106
}
@@ -159,6 +160,7 @@ async fn find_alternative_pair_price(
159
160
quote : & str ,
160
161
interval : Interval ,
161
162
timestamp : u64 ,
163
+ agg_mode : AggregationMode ,
162
164
) -> Result < ( MedianEntry , u32 ) , InfraError > {
163
165
let conn = pool. get ( ) . await . map_err ( adapt_infra_error) ?;
164
166
@@ -176,9 +178,9 @@ async fn find_alternative_pair_price(
176
178
&& pair_id_exist ( pool, alt_quote_pair. clone ( ) ) . await ?
177
179
{
178
180
let base_alt_result =
179
- get_price_decimals ( pool, base_alt_pair, interval, timestamp) . await ?;
181
+ get_price_decimals ( pool, base_alt_pair, interval, timestamp, agg_mode ) . await ?;
180
182
let alt_quote_result =
181
- get_price_decimals ( pool, alt_quote_pair, interval, timestamp) . await ?;
183
+ get_price_decimals ( pool, alt_quote_pair, interval, timestamp, agg_mode ) . await ?;
182
184
183
185
return calculate_rebased_price ( base_alt_result, alt_quote_result) ;
184
186
}
@@ -207,14 +209,109 @@ async fn get_price_decimals(
207
209
pair_id : String ,
208
210
interval : Interval ,
209
211
timestamp : u64 ,
212
+ agg_mode : AggregationMode ,
210
213
) -> Result < ( MedianEntry , u32 ) , InfraError > {
211
- let entry = get_median_price ( pool, pair_id. clone ( ) , interval, timestamp) . await ?;
214
+ let entry = match agg_mode {
215
+ AggregationMode :: Median => {
216
+ get_median_price ( pool, pair_id. clone ( ) , interval, timestamp) . await ?
217
+ }
218
+ AggregationMode :: Twap => get_twap_price ( pool, pair_id. clone ( ) , interval, timestamp) . await ?,
219
+ } ;
212
220
213
221
let decimals = get_decimals ( pool, & pair_id) . await ?;
214
222
215
223
Ok ( ( entry, decimals) )
216
224
}
217
225
226
+ pub async fn get_twap_price (
227
+ pool : & deadpool_diesel:: postgres:: Pool ,
228
+ pair_id : String ,
229
+ interval : Interval ,
230
+ time : u64 ,
231
+ ) -> Result < MedianEntry , InfraError > {
232
+ let conn = pool. get ( ) . await . map_err ( adapt_infra_error) ?;
233
+
234
+ let raw_sql = match interval {
235
+ Interval :: OneMinute => {
236
+ r#"
237
+ -- query the materialized realtime view
238
+ SELECT
239
+ bucket AS time,
240
+ price_twap AS median_price,
241
+ num_sources
242
+ FROM
243
+ twap_1_min_agg
244
+ WHERE
245
+ pair_id = $1
246
+ AND
247
+ bucket <= $2
248
+ ORDER BY
249
+ time DESC
250
+ LIMIT 1;
251
+ "#
252
+ }
253
+ Interval :: FifteenMinutes => {
254
+ r#"
255
+ -- query the materialized realtime view
256
+ SELECT
257
+ bucket AS time,
258
+ price_twap AS median_price,
259
+ num_sources
260
+ FROM
261
+ twap_15_min_agg
262
+ WHERE
263
+ pair_id = $1
264
+ AND
265
+ bucket <= $2
266
+ ORDER BY
267
+ time DESC
268
+ LIMIT 1;
269
+ "#
270
+ }
271
+ Interval :: OneHour => {
272
+ r#"
273
+ -- query the materialized realtime view
274
+ SELECT
275
+ bucket AS time,
276
+ price_twap AS median_price,
277
+ num_sources
278
+ FROM
279
+ twap_1_h_agg
280
+ WHERE
281
+ pair_id = $1
282
+ AND
283
+ bucket <= $2
284
+ ORDER BY
285
+ time DESC
286
+ LIMIT 1;
287
+ "#
288
+ }
289
+ } ;
290
+
291
+ let date_time =
292
+ NaiveDateTime :: from_timestamp_millis ( time as i64 ) . ok_or ( InfraError :: InvalidTimeStamp ) ?;
293
+
294
+ let raw_entry = conn
295
+ . interact ( move |conn| {
296
+ diesel:: sql_query ( raw_sql)
297
+ . bind :: < diesel:: sql_types:: Text , _ > ( pair_id)
298
+ . bind :: < diesel:: sql_types:: Timestamptz , _ > ( date_time)
299
+ . load :: < MedianEntryRaw > ( conn)
300
+ } )
301
+ . await
302
+ . map_err ( adapt_infra_error) ?
303
+ . map_err ( adapt_infra_error) ?;
304
+
305
+ let raw_entry = raw_entry. first ( ) . ok_or ( InfraError :: NotFound ) ?;
306
+
307
+ let entry: MedianEntry = MedianEntry {
308
+ time : raw_entry. time ,
309
+ median_price : raw_entry. median_price . clone ( ) ,
310
+ num_sources : raw_entry. num_sources ,
311
+ } ;
312
+
313
+ Ok ( entry)
314
+ }
218
315
pub async fn get_median_price (
219
316
pool : & deadpool_diesel:: postgres:: Pool ,
220
317
pair_id : String ,
0 commit comments