@@ -8,10 +8,11 @@ use pragma_entities::dto;
8
8
use pragma_entities:: {
9
9
error:: { adapt_infra_error, InfraError } ,
10
10
schema:: currencies,
11
- Entry , NewEntry ,
11
+ Currency , Entry , NewEntry ,
12
12
} ;
13
13
14
14
use crate :: handlers:: entries:: Interval ;
15
+ use crate :: utils:: { convert_via_quote, normalize_to_decimals} ;
15
16
16
17
#[ derive( Deserialize ) ]
17
18
#[ allow( unused) ]
@@ -81,6 +82,139 @@ pub struct MedianEntryRaw {
81
82
pub num_sources : i64 ,
82
83
}
83
84
85
+ pub async fn routing (
86
+ pool : & deadpool_diesel:: postgres:: Pool ,
87
+ pair_id : String ,
88
+ interval : Interval ,
89
+ timestamp : u64 ,
90
+ is_routing : bool ,
91
+ ) -> Result < ( MedianEntry , u32 ) , InfraError > {
92
+ if pair_id_exist ( pool, pair_id. clone ( ) ) . await ? || !is_routing {
93
+ return get_price_decimals ( pool, pair_id, interval, timestamp) . await ;
94
+ }
95
+
96
+ let [ base, quote] : [ & str ; 2 ] = pair_id
97
+ . split ( '/' )
98
+ . collect :: < Vec < _ > > ( )
99
+ . try_into ( )
100
+ . map_err ( |_| InfraError :: InternalServerError ) ?;
101
+
102
+ match find_alternative_pair_price ( pool, base, quote, interval, timestamp) . await {
103
+ Ok ( result) => Ok ( result) ,
104
+ Err ( _) => Err ( InfraError :: NotFound ) ,
105
+ }
106
+ }
107
+
108
+ fn calculate_rebased_price (
109
+ base_result : ( MedianEntry , u32 ) ,
110
+ quote_result : ( MedianEntry , u32 ) ,
111
+ ) -> Result < ( MedianEntry , u32 ) , InfraError > {
112
+ let ( base_entry, base_decimals) = base_result;
113
+ let ( quote_entry, quote_decimals) = quote_result;
114
+
115
+ if quote_entry. median_price == BigDecimal :: from ( 0 ) {
116
+ return Err ( InfraError :: InternalServerError ) ;
117
+ }
118
+
119
+ let ( rebase_price, decimals) = if base_decimals < quote_decimals {
120
+ let normalized_base_price =
121
+ normalize_to_decimals ( base_entry. median_price , base_decimals, quote_decimals) ;
122
+ (
123
+ convert_via_quote (
124
+ normalized_base_price,
125
+ quote_entry. median_price ,
126
+ quote_decimals,
127
+ ) ?,
128
+ quote_decimals,
129
+ )
130
+ } else {
131
+ let normalized_quote_price =
132
+ normalize_to_decimals ( quote_entry. median_price , quote_decimals, base_decimals) ;
133
+ (
134
+ convert_via_quote (
135
+ base_entry. median_price ,
136
+ normalized_quote_price,
137
+ base_decimals,
138
+ ) ?,
139
+ base_decimals,
140
+ )
141
+ } ;
142
+ let min_timestamp = std:: cmp:: max ( base_entry. time . timestamp ( ) , quote_entry. time . timestamp ( ) ) ;
143
+ let num_sources = std:: cmp:: max ( base_entry. num_sources , quote_entry. num_sources ) ;
144
+ let new_timestamp =
145
+ NaiveDateTime :: from_timestamp_opt ( min_timestamp, 0 ) . ok_or ( InfraError :: InvalidTimeStamp ) ?;
146
+
147
+ let median_entry = MedianEntry {
148
+ time : new_timestamp,
149
+ median_price : rebase_price,
150
+ num_sources,
151
+ } ;
152
+
153
+ Ok ( ( median_entry, decimals) )
154
+ }
155
+
156
+ async fn find_alternative_pair_price (
157
+ pool : & deadpool_diesel:: postgres:: Pool ,
158
+ base : & str ,
159
+ quote : & str ,
160
+ interval : Interval ,
161
+ timestamp : u64 ,
162
+ ) -> Result < ( MedianEntry , u32 ) , InfraError > {
163
+ let conn = pool. get ( ) . await . map_err ( adapt_infra_error) ?;
164
+
165
+ let alternative_currencies = conn
166
+ . interact ( Currency :: get_abstract_all)
167
+ . await
168
+ . map_err ( adapt_infra_error) ?
169
+ . map_err ( adapt_infra_error) ?;
170
+
171
+ for alt_currency in alternative_currencies {
172
+ let base_alt_pair = format ! ( "{}/{}" , base, alt_currency) ;
173
+ let alt_quote_pair = format ! ( "{}/{}" , alt_currency, quote) ;
174
+
175
+ if pair_id_exist ( pool, base_alt_pair. clone ( ) ) . await ?
176
+ && pair_id_exist ( pool, alt_quote_pair. clone ( ) ) . await ?
177
+ {
178
+ let base_alt_result =
179
+ get_price_decimals ( pool, base_alt_pair, interval, timestamp) . await ?;
180
+ let alt_quote_result =
181
+ get_price_decimals ( pool, alt_quote_pair, interval, timestamp) . await ?;
182
+
183
+ return calculate_rebased_price ( base_alt_result, alt_quote_result) ;
184
+ }
185
+ }
186
+
187
+ Err ( InfraError :: NotFound )
188
+ }
189
+
190
+ async fn pair_id_exist (
191
+ pool : & deadpool_diesel:: postgres:: Pool ,
192
+ pair_id : String ,
193
+ ) -> Result < bool , InfraError > {
194
+ let conn = pool. get ( ) . await . map_err ( adapt_infra_error) ?;
195
+
196
+ let res = conn
197
+ . interact ( move |conn| Entry :: exists ( conn, pair_id) )
198
+ . await
199
+ . map_err ( adapt_infra_error) ?
200
+ . map_err ( adapt_infra_error) ?;
201
+
202
+ Ok ( res)
203
+ }
204
+
205
+ async fn get_price_decimals (
206
+ pool : & deadpool_diesel:: postgres:: Pool ,
207
+ pair_id : String ,
208
+ interval : Interval ,
209
+ timestamp : u64 ,
210
+ ) -> Result < ( MedianEntry , u32 ) , InfraError > {
211
+ let entry = get_median_price ( pool, pair_id. clone ( ) , interval, timestamp) . await ?;
212
+
213
+ let decimals = get_decimals ( pool, & pair_id) . await ?;
214
+
215
+ Ok ( ( entry, decimals) )
216
+ }
217
+
84
218
pub async fn get_median_price (
85
219
pool : & deadpool_diesel:: postgres:: Pool ,
86
220
pair_id : String ,
0 commit comments